| 226 | | ## Code gen |
| 227 | | |
| 228 | | def writeSharpDefInContext(sw as SharpWriter) |
| 229 | | .writeSharpDefInContext(sw, true) |
| 230 | | |
| 231 | | def writeSharpDefInContext(sw as SharpWriter, parens as bool) |
| 232 | | """ |
| 233 | | When an expression is used where a particular type is expected, such as: |
| 234 | | # assignment |
| 235 | | x = y |
| 236 | | # argument passing |
| 237 | | obj.foo(x, y) |
| 238 | | obj[x, y] |
| 239 | | it may need C# typecasting--particularly if it is dynamic typed expression. |
| 240 | | This method relies on having had its .contextType set beforehand. |
| 241 | | This method should be invoked instead of `writeSharpDef` in any situation where .contextType was set. |
| 242 | | """ |
| 243 | | type = .type |
| 244 | | cast = false |
| 245 | | if _contextType |
| 246 | | if type.isDynamic |
| 247 | | cast = true |
| 248 | | else if type inherits IntType |
| 249 | | if type.size < 32, cast = true |
| 250 | | if cast |
| 251 | | if parens, sw.write('(') |
| 252 | | sw.write('([_contextType.sharpRef])(') |
| 253 | | .writeSharpDef(sw) |
| 254 | | if cast |
| 255 | | sw.write(')') |
| 256 | | if parens, sw.write(')') |
| 257 | | |
| 258 | | def writeSharpDef(sw as SharpWriter) is override |
| 259 | | base.writeSharpDef(sw) |
| 260 | | branch .argumentLabel |
| 261 | | on ArgumentLabel.None, pass |
| 262 | | on ArgumentLabel.Out, sw.write('out ') |
| 263 | | on ArgumentLabel.InOut, sw.write('ref ') |
| 264 | | .writeSharpDef(sw, true) |
| 265 | | |
| 266 | | def writeSharpDef(sw as SharpWriter, parens as bool) |
| 267 | | pass |
| 268 | | |
| 269 | | def writeSharpStmt(sw as SharpWriter) is override |
| 270 | | assert .didBindImp |
| 271 | | sw.node(this) |
| 272 | | .writeSharpSetLine(sw) |
| 273 | | .writeSharpDef(sw, false) |
| 274 | | sw.write(';\n') |
| 275 | | |
| 276 | | def writeSharpBreakdown(sw as SharpWriter) |
| 277 | | sw.write(r'new object[] { 0') |
| 278 | | .writeSharpBreakdownItems(sw) |
| 279 | | sw.write('}, ') |
| 280 | | |
| 281 | | get willWriteSharpBreakdownItems as bool |
| 282 | | return _argumentLabel <> ArgumentLabel.Out |
| 283 | | |
| 284 | | def writeSharpBreakdownItems(sw as SharpWriter) |
| 285 | | if .willWriteSharpBreakdownItems |
| 286 | | src = Utils.sharpStringLiteralFor(.toCobraSource) |
| 287 | | sw.write(', [src], ') |
| 288 | | .writeSharpDefForBreakdown(sw) |
| 289 | | |
| 290 | | def writeSharpDefForBreakdown(sw as SharpWriter) |
| 291 | | .writeSharpDef(sw) |
| 292 | | |
| 293 | | |
| 725 | | def writeSharpDef(sw as SharpWriter, parens as bool) is override |
| 726 | | assert .superNode inherits DotExpr |
| 727 | | name = .name |
| 728 | | if _definition inherits BoxMember and (_definition to BoxMember).binaryName |
| 729 | | name = (_definition to BoxMember).binaryName to ! |
| 730 | | else |
| 731 | | name = name.capped |
| 732 | | sw.write('[name]') |
| 733 | | if _genericArgTypes and _genericArgTypes.count |
| 734 | | sw.write('<') |
| 735 | | sep = '' |
| 736 | | for genericArgType in _genericArgTypes |
| 737 | | sw.write(sep + genericArgType.sharpRef) |
| 738 | | sep = ', ' |
| 739 | | sw.write('>') |
| 740 | | sw.write('(') |
| 741 | | sep = '' |
| 742 | | for arg in _args |
| 743 | | sw.write(sep) |
| 744 | | arg.writeSharpDefInContext(sw) |
| 745 | | sep = ', ' |
| 746 | | sw.write(')') |
| 747 | | |
| 748 | | def writeSharpBreakdownItems(sw as SharpWriter) is override |
| 749 | | # leaving out the base call is intentional: |
| 750 | | # base.writeSharpBreakdownItems(sw) |
| 751 | | sw.write(', +1') |
| 752 | | for expr in _args |
| 753 | | expr.writeSharpBreakdownItems(sw) |
| 754 | | sw.write(', -1') |
| 755 | | |
| 911 | | def writeSharpDef(sw as SharpWriter, parens as bool) is override |
| 912 | | # C#: CobraImp.For(stuff, delegate(x as int) { return x*x }) |
| 913 | | # C#: CobraImp.For(stuff, delegate(x as int) { if (x<0) return x*x; }) |
| 914 | | inType = _what.type.innerType |
| 915 | | outType = _getExpr.type |
| 916 | | sw.write('CobraImp.For<[inType.sharpRef],[outType.sharpRef]>(') |
| 917 | | _what.writeSharpDef(sw, false) |
| 918 | | sw.write(', ') |
| 919 | | helperName = '_lh_for_[_var.name]_[_varNumber]' |
| 920 | | if _whereExpr is nil |
| 921 | | sw.write('delegate([inType.sharpRef] [helperName]) {\n') |
| 922 | | sw.indent |
| 923 | | sw.write('[_var.sharpName] = [helperName];\n') |
| 924 | | sw.write('return ') |
| 925 | | _getExpr.writeSharpDef(sw, false) |
| 926 | | sw.write(';\n') |
| 927 | | sw.dedent |
| 928 | | sw.write('})') |
| 929 | | else |
| 930 | | outHelperName = helperName + '_out' |
| 931 | | sw.write('delegate([inType.sharpRef] [helperName], out [outType.sharpRef] [outHelperName]) {\n') |
| 932 | | sw.indent |
| 933 | | sw.write('[_var.sharpName] = [helperName];\n') |
| 934 | | sw.write('if (') |
| 935 | | _whereExpr.writeSharpDef(sw, false) |
| 936 | | sw.write(') {\n') |
| 937 | | sw.indent |
| 938 | | sw.write('[outHelperName] = ') |
| 939 | | _getExpr.writeSharpDef(sw, false) |
| 940 | | sw.write(';\n') |
| 941 | | sw.write('return true;\n') |
| 942 | | sw.dedent |
| 943 | | sw.write('} else {\n') |
| 944 | | sw.indent |
| 945 | | sw.write('[outHelperName] = [outType.sharpInit];\n') |
| 946 | | sw.write('return false;\n') |
| 947 | | sw.dedent |
| 948 | | sw.write('}\n') |
| 949 | | sw.dedent |
| 950 | | sw.write('})') |
| 951 | | |
| 1079 | | def writeSharpDef(sw as SharpWriter, parens as bool) is override |
| 1080 | | # weird stuff motivated by ../Tests/110-basics-two/500-namespaces/400-type-property-name-collision-1.cobra and 402-type-property-name-collision-2.cobra |
| 1081 | | |
| 1082 | | # recall that this cannot be the right side of "foo.bar" since that is a MemberExpr |
| 1083 | | sharpName = .sharpName |
| 1084 | | if not .definition inherits IVar |
| 1085 | | # the only definition that has no parentNameSpace in practice is IVar |
| 1086 | | if not sharpName.startsWith('typeof') |
| 1087 | | # maybe parentNameSpace could be moved up in the interface definitions |
| 1088 | | pn = (.definition to dynamic).parentNameSpace |
| 1089 | | if pn, sharpName = pn.sharpQualifier + sharpName |
| 1090 | | |
| 1091 | | # handle the case of "X.X" where namespace and class are both called "X". |
| 1092 | | # C# chokes on it because the first "X" is considered to be the type |
| 1093 | | if .curBox.name + '.' in sharpName |
| 1094 | | sharpName = 'global::' + sharpName |
| 1095 | | |
| 1096 | | sw.write(sharpName) |
| 1097 | | |
| 1098 | | get sharpName as String |
| 1099 | | assert .didBindImp |
| 1100 | | assert .definition |
| 1101 | | assert not .type inherits UnspecifiedType |
| 1102 | | if .superNode inherits DotExpr |
| 1103 | | assert this is not (.superNode to DotExpr).right # should be a CallExpr or MemberExpr instead |
| 1104 | | defi = .definition |
| 1105 | | if .isTypeReference |
| 1106 | | # C# often requires typeof(Foo) instead of just plain Foo |
| 1107 | | superNode = .superNode |
| 1108 | | if not superNode inherits DotExpr and not superNode inherits InheritsExpr and (not superNode inherits PostCallExpr or (superNode to PostCallExpr).expr is not this) |
| 1109 | | return 'typeof(' + defi.sharpName + ')' |
| 1110 | | return defi.sharpName |
| 1111 | | |
| 1112 | | def writeSharpStmt(sw as SharpWriter) is override |
| 1113 | | assert .isCalling |
| 1114 | | sw.write('[_name]();') |
| 1115 | | |
| 1116 | | get sharpAssignmentNames as List<of String>? |
| 1117 | | require |
| 1118 | | .didBindImp |
| 1119 | | .definition |
| 1120 | | body |
| 1121 | | if _definition inherits IVar |
| 1122 | | return _definition.sharpAssignmentNames |
| 1123 | | else |
| 1124 | | return nil |
| 1125 | | |
| 1126 | | def writeSharpDefForBreakdown(sw as SharpWriter) |
| 1127 | | sharpName = .sharpName |
| 1128 | | if .isKindOf(.compiler.typeType) and .definition inherits IType and 'typeof(' not in sharpName |
| 1129 | | sw.write('typeof([.sharpName])') |
| 1130 | | else |
| 1131 | | base.writeSharpDefForBreakdown(sw) |
| 1132 | | |
| 1213 | | def writeSharpBreakdownItems(sw as SharpWriter) |
| 1214 | | base.writeSharpBreakdownItems(sw) |
| 1215 | | |
| 1216 | | sw.write(', +1') # indent |
| 1217 | | |
| 1218 | | _cond.writeSharpBreakdownItems(sw) |
| 1219 | | # only one of the target expressions is actually evaluated |
| 1220 | | |
| 1221 | | # tpart: |
| 1222 | | src = Utils.sharpStringLiteralFor(_tpart.toCobraSource) |
| 1223 | | sw.write(', [src], new CobraDirectString(') |
| 1224 | | _cond.writeSharpDefForBreakdown(sw) |
| 1225 | | sw.write(' ? CobraCore.ToTechString(') |
| 1226 | | _tpart.writeSharpDefForBreakdown(sw) |
| 1227 | | sw.write(') : "(not-evaluated)")') |
| 1228 | | |
| 1229 | | # fpart: |
| 1230 | | src = Utils.sharpStringLiteralFor(_fpart.toCobraSource) |
| 1231 | | sw.write(', [src], new CobraDirectString(') |
| 1232 | | _cond.writeSharpDefForBreakdown(sw) |
| 1233 | | sw.write(' ? "(not-evaluated)" : CobraCore.ToTechString(') |
| 1234 | | _fpart.writeSharpDefForBreakdown(sw) |
| 1235 | | sw.write('))') |
| 1236 | | |
| 1237 | | sw.write(', -1') # dedent |
| 1238 | | |
| 1356 | | def writeSharpDef(sw as SharpWriter, parens as bool) is override |
| 1357 | | if _target.type.isDynamic |
| 1358 | | sw.write('CobraImp.GetIndexerValue(') |
| 1359 | | _target.writeSharpDef(sw, false) |
| 1360 | | for expr in _args |
| 1361 | | sw.write(', ') |
| 1362 | | expr.writeSharpDef(sw, false) |
| 1363 | | sw.write(')') |
| 1364 | | return |
| 1365 | | if parens |
| 1366 | | sw.write('(') |
| 1367 | | if _target inherits IdentifierExpr |
| 1368 | | if _target.isKindOf(.compiler.typeType) |
| 1369 | | # here we're favoring "Foo[]" being an array type rather than a shared indexer |
| 1370 | | sw.write(_target.name) |
| 1371 | | handled = true |
| 1372 | | if not handled |
| 1373 | | _target.writeSharpDef(sw) |
| 1374 | | sw.write(r'[') |
| 1375 | | sep = '' |
| 1376 | | for expr in _args |
| 1377 | | sw.write(sep) |
| 1378 | | expr.writeSharpDefInContext(sw) |
| 1379 | | sep = ', ' |
| 1380 | | sw.write(']') |
| 1381 | | if parens |
| 1382 | | sw.write(')') |
| 1383 | | |
| 1384 | | def writeSharpBreakdownItems(sw as SharpWriter) |
| 1385 | | base.writeSharpBreakdownItems(sw) |
| 1386 | | sw.write(', +1') |
| 1387 | | _target.writeSharpBreakdownItems(sw) |
| 1388 | | for expr in _args |
| 1389 | | expr.writeSharpBreakdownItems(sw) |
| 1390 | | sw.write(', -1') |
| 1391 | | |
| 1812 | | def writeSharpDef(sw as SharpWriter, parens as bool) is override |
| 1813 | | if parens, sw.write('(') |
| 1814 | | expr = _expr |
| 1815 | | isMethodSig = false |
| 1816 | | isDynamic = false |
| 1817 | | if expr inherits TypeExpr |
| 1818 | | if expr.containedType inherits ArrayType |
| 1819 | | # arrays |
| 1820 | | sw.write('new ') |
| 1821 | | sw.write((expr.containedType to ArrayType).theWrappedType.sharpRef) |
| 1822 | | sw.write(r'[') |
| 1823 | | .writeSharpArgs(sw) |
| 1824 | | sw.write(r']') |
| 1825 | | else |
| 1826 | | sw.write('new ') |
| 1827 | | expr.writeSharpDef(sw) |
| 1828 | | sw.write('(') |
| 1829 | | .writeSharpArgs(sw) |
| 1830 | | sw.write(')') |
| 1831 | | else if expr inherits IdentifierExpr |
| 1832 | | if expr.isTypeReference |
| 1833 | | sw.write('new ') |
| 1834 | | expr.writeSharpDef(sw) |
| 1835 | | sw.write('(') |
| 1836 | | .writeSharpArgs(sw) |
| 1837 | | sw.write(')') |
| 1838 | | else if expr.receiverType inherits GenericParam # TODO: shouldn't expr.isTypeReference above have caught this? |
| 1839 | | sw.write('new [expr.receiverType.sharpRef](') |
| 1840 | | .writeSharpArgs(sw) |
| 1841 | | sw.write(')') |
| 1842 | | else if expr.type inherits MethodSig |
| 1843 | | isMethodSig = true |
| 1844 | | else if expr.type.isSystemTypeClass or _type.isDynamic |
| 1845 | | isDynamic = true |
| 1846 | | else |
| 1847 | | assert false, expr # TODO: .throwError |
| 1848 | | else if expr inherits IndexExpr |
| 1849 | | if expr.type inherits MethodSig |
| 1850 | | isMethodSig = true |
| 1851 | | else if expr.type.isSystemTypeClass or _type.isDynamic |
| 1852 | | isDynamic = true |
| 1853 | | else |
| 1854 | | assert false, expr # TODO: .throwError |
| 1855 | | else |
| 1856 | | assert false, expr # TODO: .throwError |
| 1857 | | if isMethodSig |
| 1858 | | expr.writeSharpDef(sw) |
| 1859 | | sw.write('(') |
| 1860 | | .writeSharpArgs(sw) |
| 1861 | | sw.write(')') |
| 1862 | | else if isDynamic |
| 1863 | | defi = (expr to dynamic).definition |
| 1864 | | assert not defi inherits Box, expr # TODO: just curious |
| 1865 | | what = if(defi inherits IType, 'typeof([defi.sharpName])', defi.sharpName to String) |
| 1866 | | if defi inherits IVar |
| 1867 | | if defi.type.isDynamic |
| 1868 | | what = '(System.Type)' + what |
| 1869 | | sw.write('Activator.CreateInstance([what]') |
| 1870 | | .writeSharpArgs(sw, ', ') |
| 1871 | | sw.write(')') |
| 1872 | | if parens, sw.write(')') |
| 1873 | | |
| 1874 | | def writeSharpArgs(sw as SharpWriter) |
| 1875 | | .writeSharpArgs(sw, '') |
| 1876 | | |
| 1877 | | def writeSharpArgs(sw as SharpWriter, sep as String) |
| 1878 | | for arg in _args |
| 1879 | | sw.write(sep) |
| 1880 | | arg.writeSharpDefInContext(sw, false) |
| 1881 | | sep = ',' |
| 1882 | | |
| 1883 | | def writeSharpBreakdownItems(sw as SharpWriter) |
| 1884 | | base.writeSharpBreakdownItems(sw) |
| 1885 | | sw.write(', +1') |
| 1886 | | _expr.writeSharpBreakdownItems(sw) |
| 1887 | | for expr in _args |
| 1888 | | expr.writeSharpBreakdownItems(sw) |
| 1889 | | sw.write(', -1') |
| 1890 | | |