| | 1386 | |
|---|
| | 1387 | |
|---|
| | 1388 | /** |
|---|
| | 1389 | $(D AutoImplement), by default, automatically implements all abstract member |
|---|
| | 1390 | functions in the class or interface $(D Base) as do-nothing functions. |
|---|
| | 1391 | |
|---|
| | 1392 | -------------------- |
|---|
| | 1393 | abstract class Base |
|---|
| | 1394 | { |
|---|
| | 1395 | int m_value; |
|---|
| | 1396 | this(int v) { m_value = v; } |
|---|
| | 1397 | int value() @property { return m_value; } |
|---|
| | 1398 | |
|---|
| | 1399 | abstract real realValue() @property; |
|---|
| | 1400 | abstract void doSomething(); |
|---|
| | 1401 | } |
|---|
| | 1402 | |
|---|
| | 1403 | void main() |
|---|
| | 1404 | { |
|---|
| | 1405 | auto obj = new AutoImplement!Base(42); |
|---|
| | 1406 | writeln(obj.value); // prints "42" |
|---|
| | 1407 | |
|---|
| | 1408 | // Abstract functions are implemented as do-nothing: |
|---|
| | 1409 | writeln(obj.realValue); // prints "NaN" |
|---|
| | 1410 | obj.doSomething(); // does nothing |
|---|
| | 1411 | } |
|---|
| | 1412 | -------------------- |
|---|
| | 1413 | |
|---|
| | 1414 | The behavior can be customized with the parameters. |
|---|
| | 1415 | |
|---|
| | 1416 | Params: |
|---|
| | 1417 | how = A template which determines _how functions will be |
|---|
| | 1418 | implemented/overridden. |
|---|
| | 1419 | |
|---|
| | 1420 | Two arguments are passed to $(D how): the first one is the $(D Base), |
|---|
| | 1421 | and the second one is an alias to a function to be implemented. Then |
|---|
| | 1422 | $(D how) must return a implemented function body as a string. |
|---|
| | 1423 | |
|---|
| | 1424 | The generated function body can use these keywords: |
|---|
| | 1425 | $(UL |
|---|
| | 1426 | $(LI $(D a0), $(D a1), …: arguments passed to the function;) |
|---|
| | 1427 | $(LI $(D args): a tuple of the arguments;) |
|---|
| | 1428 | $(LI $(D self): an alias to the function itself;) |
|---|
| | 1429 | $(LI $(D parent): an alias to the overridden function (if any).) |
|---|
| | 1430 | ) |
|---|
| | 1431 | |
|---|
| | 1432 | You may want to use templated property functions (instead of Implicit |
|---|
| | 1433 | Template Properties) to generate complex functions: |
|---|
| | 1434 | -------------------- |
|---|
| | 1435 | // Prints log messages for each call to overridden functions. |
|---|
| | 1436 | string generateLogger(C, alias fun)() @property |
|---|
| | 1437 | { |
|---|
| | 1438 | enum qname = C.stringof ~ "." ~ __traits(identifier, fun); |
|---|
| | 1439 | string stmt; |
|---|
| | 1440 | |
|---|
| | 1441 | stmt ~= q{ struct Importer { import std.stdio; } }; |
|---|
| | 1442 | stmt ~= `Importer.writeln$(LPAREN)"Log: ` ~ qname ~ `(", args, ")"$(RPAREN);`; |
|---|
| | 1443 | static if (!__traits(isAbstractFunction, fun)) |
|---|
| | 1444 | { |
|---|
| | 1445 | static if (is(typeof(return) == void)) |
|---|
| | 1446 | stmt ~= q{ parent(args); }; |
|---|
| | 1447 | else |
|---|
| | 1448 | stmt ~= q{ |
|---|
| | 1449 | auto r = parent(args); |
|---|
| | 1450 | Importer.writeln("--> ", r); |
|---|
| | 1451 | return r; |
|---|
| | 1452 | }; |
|---|
| | 1453 | } |
|---|
| | 1454 | return stmt; |
|---|
| | 1455 | } |
|---|
| | 1456 | -------------------- |
|---|
| | 1457 | |
|---|
| | 1458 | what = A template which determines _what functions should be |
|---|
| | 1459 | implemented/overridden. |
|---|
| | 1460 | |
|---|
| | 1461 | An argument is passed to $(D what): an alias to a non-final member |
|---|
| | 1462 | function in $(D Base). Then $(D what) must return a boolean value. |
|---|
| | 1463 | Return $(D true) to indicate that the passed function should be |
|---|
| | 1464 | implemented/overridden. |
|---|
| | 1465 | |
|---|
| | 1466 | -------------------- |
|---|
| | 1467 | // Sees if fun returns something. |
|---|
| | 1468 | template hasValue(alias fun) |
|---|
| | 1469 | { |
|---|
| | 1470 | enum bool hasValue = !is(ReturnType!(fun) == void); |
|---|
| | 1471 | } |
|---|
| | 1472 | -------------------- |
|---|
| | 1473 | |
|---|
| | 1474 | |
|---|
| | 1475 | Note: |
|---|
| | 1476 | |
|---|
| | 1477 | Generated code is inserted in the scope of $(D std.typecons) module. Thus, |
|---|
| | 1478 | any useful functions outside $(D std.typecons) cannot be used in the generated |
|---|
| | 1479 | code. To workaround this problem, you may $(D import) necessary things in a |
|---|
| | 1480 | local struct, as done in the $(D generateLogger()) template in the above |
|---|
| | 1481 | example. |
|---|
| | 1482 | |
|---|
| | 1483 | |
|---|
| | 1484 | BUGS: |
|---|
| | 1485 | |
|---|
| | 1486 | $(UL |
|---|
| | 1487 | $(LI Variadic arguments to constructors are not forwarded to super.) |
|---|
| | 1488 | $(LI Deep interface inheritance causes compile error with messages like |
|---|
| | 1489 | "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar |
|---|
| | 1490 | does not override any function". [$(BUGZILLA 2525), $(BUGZILLA 3525)] ) |
|---|
| | 1491 | $(LI The $(D parent) keyword is actually a delegate to the super class' |
|---|
| | 1492 | corresponding member function. [$(BUGZILLA 2540)] ) |
|---|
| | 1493 | $(LI Using $(D alias) template parameter in $(D how) and/or $(D what) may |
|---|
| | 1494 | cause strange compile error. Use template tuple parameter instead to |
|---|
| | 1495 | workaround this problem. [$(BUGZILLA 4217)] ) |
|---|
| | 1496 | ) |
|---|
| | 1497 | */ |
|---|
| | 1498 | class AutoImplement( Base, |
|---|
| | 1499 | alias how = generateEmptyFunction, alias what = isAbstractFunction ) |
|---|
| | 1500 | : Base |
|---|
| | 1501 | { |
|---|
| | 1502 | private alias AutoImplement_Helper!( |
|---|
| | 1503 | "autoImplement_helper_", "Base", Base, how, what ) |
|---|
| | 1504 | autoImplement_helper_; |
|---|
| | 1505 | override mixin(autoImplement_helper_.code); |
|---|
| | 1506 | } |
|---|
| | 1507 | |
|---|
| | 1508 | /* |
|---|
| | 1509 | * Code-generating stuffs are encupsulated in this helper template so that |
|---|
| | 1510 | * namespace pollusion, which can cause name confliction with Base's public |
|---|
| | 1511 | * members, should be minimized. |
|---|
| | 1512 | */ |
|---|
| | 1513 | private template AutoImplement_Helper(string myName, string baseName, |
|---|
| | 1514 | Base, alias generateMethodBody, alias cherrypickMethod) |
|---|
| | 1515 | { |
|---|
| | 1516 | private static: |
|---|
| | 1517 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1518 | // Internal stuffs |
|---|
| | 1519 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1520 | |
|---|
| | 1521 | // this would be deprecated by std.typelist.Filter |
|---|
| | 1522 | template staticFilter(alias pred, lst...) |
|---|
| | 1523 | { |
|---|
| | 1524 | alias staticFilterImpl!(pred, lst).result staticFilter; |
|---|
| | 1525 | } |
|---|
| | 1526 | template staticFilterImpl(alias pred, lst...) |
|---|
| | 1527 | { |
|---|
| | 1528 | static if (lst.length > 0) |
|---|
| | 1529 | { |
|---|
| | 1530 | alias staticFilterImpl!(pred, lst[1 .. $]).result tail; |
|---|
| | 1531 | // |
|---|
| | 1532 | static if (true && pred!(lst[0])) |
|---|
| | 1533 | alias TypeTuple!(lst[0], tail) result; |
|---|
| | 1534 | else |
|---|
| | 1535 | alias tail result; |
|---|
| | 1536 | } |
|---|
| | 1537 | else |
|---|
| | 1538 | alias TypeTuple!() result; |
|---|
| | 1539 | } |
|---|
| | 1540 | |
|---|
| | 1541 | // Returns function overload sets in the class C, filtered with pred. |
|---|
| | 1542 | template enumerateOverloads(C, alias pred) |
|---|
| | 1543 | { |
|---|
| | 1544 | alias enumerateOverloadsImpl!(C, pred, traits_allMembers!(C)).result |
|---|
| | 1545 | enumerateOverloads; |
|---|
| | 1546 | } |
|---|
| | 1547 | template enumerateOverloadsImpl(C, alias pred, names...) |
|---|
| | 1548 | { |
|---|
| | 1549 | static if (names.length > 0) |
|---|
| | 1550 | { |
|---|
| | 1551 | alias staticFilter!(pred, MemberFunctionsTuple!(C, ""~names[0])) methods; |
|---|
| | 1552 | alias enumerateOverloadsImpl!(C, pred, names[1 .. $]).result next; |
|---|
| | 1553 | |
|---|
| | 1554 | static if (methods.length > 0) |
|---|
| | 1555 | alias TypeTuple!(OverloadSet!(""~names[0], methods), next) result; |
|---|
| | 1556 | else |
|---|
| | 1557 | alias next result; |
|---|
| | 1558 | } |
|---|
| | 1559 | else |
|---|
| | 1560 | alias TypeTuple!() result; |
|---|
| | 1561 | } |
|---|
| | 1562 | |
|---|
| | 1563 | |
|---|
| | 1564 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1565 | // Target functions |
|---|
| | 1566 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1567 | |
|---|
| | 1568 | // Add a non-final check to the cherrypickMethod. |
|---|
| | 1569 | template canonicalPicker(fun.../+[BUG 4217]+/) |
|---|
| | 1570 | { |
|---|
| | 1571 | enum bool canonicalPicker = !__traits(isFinalFunction, fun[0]) && |
|---|
| | 1572 | cherrypickMethod!(fun); |
|---|
| | 1573 | } |
|---|
| | 1574 | |
|---|
| | 1575 | /* |
|---|
| | 1576 | * A tuple of overload sets, each item of which consists of functions to be |
|---|
| | 1577 | * implemented by the generated code. |
|---|
| | 1578 | */ |
|---|
| | 1579 | alias enumerateOverloads!(Base, canonicalPicker) targetOverloadSets; |
|---|
| | 1580 | |
|---|
| | 1581 | /* |
|---|
| | 1582 | * A tuple of the super class' constructors. Used for forwarding |
|---|
| | 1583 | * constructor calls. |
|---|
| | 1584 | */ |
|---|
| | 1585 | static if (__traits(hasMember, Base, "__ctor")) |
|---|
| | 1586 | alias OverloadSet!("__ctor", __traits(getOverloads, Base, "__ctor")) |
|---|
| | 1587 | ctorOverloadSet; |
|---|
| | 1588 | else |
|---|
| | 1589 | alias OverloadSet!("__ctor") ctorOverloadSet; // empty |
|---|
| | 1590 | |
|---|
| | 1591 | |
|---|
| | 1592 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1593 | // Type information |
|---|
| | 1594 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1595 | |
|---|
| | 1596 | /* |
|---|
| | 1597 | * The generated code will be mixed into AutoImplement, which will be |
|---|
| | 1598 | * instantiated in this module's scope. Thus, any user-defined types are |
|---|
| | 1599 | * out of scope and cannot be used directly (i.e. by their names). |
|---|
| | 1600 | * |
|---|
| | 1601 | * We will use FuncInfo instances for accessing return types and parameter |
|---|
| | 1602 | * types of the implemented functions. The instances will be populated to |
|---|
| | 1603 | * the AutoImplement's scope in a certain way; see the populate() below. |
|---|
| | 1604 | */ |
|---|
| | 1605 | |
|---|
| | 1606 | // Returns the preferred identifier for the FuncInfo instance for the i-th |
|---|
| | 1607 | // overloaded function with the name. |
|---|
| | 1608 | template INTERNAL_FUNCINFO_ID(string name, size_t i) |
|---|
| | 1609 | { |
|---|
| | 1610 | enum string INTERNAL_FUNCINFO_ID = "F_" ~ name ~ "_" ~ toStringNow!(i); |
|---|
| | 1611 | } |
|---|
| | 1612 | |
|---|
| | 1613 | /* |
|---|
| | 1614 | * Insert FuncInfo instances about all the target functions here. This |
|---|
| | 1615 | * enables the generated code to access type information via, for example, |
|---|
| | 1616 | * "autoImplement_helper_.F_foo_1". |
|---|
| | 1617 | */ |
|---|
| | 1618 | template populate(overloads...) |
|---|
| | 1619 | { |
|---|
| | 1620 | static if (overloads.length > 0) |
|---|
| | 1621 | { |
|---|
| | 1622 | mixin populate!(overloads[0].name, overloads[0].contents); |
|---|
| | 1623 | mixin populate!(overloads[1 .. $]); |
|---|
| | 1624 | } |
|---|
| | 1625 | } |
|---|
| | 1626 | template populate(string name, methods...) |
|---|
| | 1627 | { |
|---|
| | 1628 | static if (methods.length > 0) |
|---|
| | 1629 | { |
|---|
| | 1630 | mixin populate!(name, methods[0 .. $ - 1]); |
|---|
| | 1631 | // |
|---|
| | 1632 | alias methods[$ - 1] target; |
|---|
| | 1633 | enum ith = methods.length - 1; |
|---|
| | 1634 | mixin( "alias FuncInfo!(target) " ~ |
|---|
| | 1635 | INTERNAL_FUNCINFO_ID!(name, ith) ~ ";" ); |
|---|
| | 1636 | } |
|---|
| | 1637 | } |
|---|
| | 1638 | |
|---|
| | 1639 | public mixin populate!(targetOverloadSets); |
|---|
| | 1640 | public mixin populate!( ctorOverloadSet ); |
|---|
| | 1641 | |
|---|
| | 1642 | |
|---|
| | 1643 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1644 | // Code-generating policies |
|---|
| | 1645 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1646 | |
|---|
| | 1647 | /* Common policy configurations for generating constructors and methods. */ |
|---|
| | 1648 | template CommonGeneratingPolicy() |
|---|
| | 1649 | { |
|---|
| | 1650 | // base class identifier which generated code should use |
|---|
| | 1651 | enum string BASE_CLASS_ID = baseName; |
|---|
| | 1652 | |
|---|
| | 1653 | // FuncInfo instance identifier which generated code should use |
|---|
| | 1654 | template FUNCINFO_ID(string name, size_t i) |
|---|
| | 1655 | { |
|---|
| | 1656 | enum string FUNCINFO_ID = |
|---|
| | 1657 | myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i); |
|---|
| | 1658 | } |
|---|
| | 1659 | |
|---|
| | 1660 | // preferred identifier for i-th parameter variable |
|---|
| | 1661 | template PARAMETER_VARIABLE_ID(size_t i) |
|---|
| | 1662 | { |
|---|
| | 1663 | enum string PARAMETER_VARIABLE_ID = "a" ~ toStringNow!(i); |
|---|
| | 1664 | } |
|---|
| | 1665 | } |
|---|
| | 1666 | |
|---|
| | 1667 | /* Policy configurations for generating constructors. */ |
|---|
| | 1668 | template ConstructorGeneratingPolicy() |
|---|
| | 1669 | { |
|---|
| | 1670 | mixin CommonGeneratingPolicy; |
|---|
| | 1671 | |
|---|
| | 1672 | /* Generates constructor body. Just forward to the base class' one. */ |
|---|
| | 1673 | string generateFunctionBody(ctor.../+[BUG 4217]+/)() @property |
|---|
| | 1674 | { |
|---|
| | 1675 | enum varstyle = variadicFunctionStyle!(typeof(&ctor[0])); |
|---|
| | 1676 | |
|---|
| | 1677 | static if (varstyle & (Variadic.C | Variadic.D)) |
|---|
| | 1678 | { |
|---|
| | 1679 | // the argptr-forwarding problem |
|---|
| | 1680 | pragma(msg, "Warning: AutoImplement!(", Base, ") ", |
|---|
| | 1681 | "ignored variadic arguments to the constructor ", |
|---|
| | 1682 | FunctionTypeOf!(typeof(&ctor[0])) ); |
|---|
| | 1683 | } |
|---|
| | 1684 | return "super(args);"; |
|---|
| | 1685 | } |
|---|
| | 1686 | } |
|---|
| | 1687 | |
|---|
| | 1688 | /* Policy configurations for genearting target methods. */ |
|---|
| | 1689 | template MethodGeneratingPolicy() |
|---|
| | 1690 | { |
|---|
| | 1691 | mixin CommonGeneratingPolicy; |
|---|
| | 1692 | |
|---|
| | 1693 | /* Geneartes method body. */ |
|---|
| | 1694 | string generateFunctionBody(func.../+[BUG 4217]+/)() @property |
|---|
| | 1695 | { |
|---|
| | 1696 | return generateMethodBody!(Base, func); // given |
|---|
| | 1697 | } |
|---|
| | 1698 | } |
|---|
| | 1699 | |
|---|
| | 1700 | |
|---|
| | 1701 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1702 | // Generated code |
|---|
| | 1703 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1704 | |
|---|
| | 1705 | alias MemberFunctionGenerator!( ConstructorGeneratingPolicy!() ) |
|---|
| | 1706 | ConstructorGenerator; |
|---|
| | 1707 | alias MemberFunctionGenerator!( MethodGeneratingPolicy!() ) |
|---|
| | 1708 | MethodGenerator; |
|---|
| | 1709 | |
|---|
| | 1710 | public enum string code = |
|---|
| | 1711 | ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~ |
|---|
| | 1712 | MethodGenerator.generateCode!(targetOverloadSets); |
|---|
| | 1713 | |
|---|
| | 1714 | debug (SHOW_GENERATED_CODE) |
|---|
| | 1715 | { |
|---|
| | 1716 | pragma(msg, "-------------------- < ", Base, " >"); |
|---|
| | 1717 | pragma(msg, code); |
|---|
| | 1718 | pragma(msg, "--------------------"); |
|---|
| | 1719 | } |
|---|
| | 1720 | } |
|---|
| | 1721 | |
|---|
| | 1722 | //debug = SHOW_GENERATED_CODE; |
|---|
| | 1723 | unittest |
|---|
| | 1724 | { |
|---|
| | 1725 | // no function to implement |
|---|
| | 1726 | { |
|---|
| | 1727 | interface I_1 {} |
|---|
| | 1728 | auto o = new AutoImplement!I_1; |
|---|
| | 1729 | } |
|---|
| | 1730 | // return value |
|---|
| | 1731 | { |
|---|
| | 1732 | interface I_2 { real test(); } |
|---|
| | 1733 | auto o = new AutoImplement!I_2; |
|---|
| | 1734 | assert(o.test() !<>= 0); // NaN |
|---|
| | 1735 | } |
|---|
| | 1736 | // parameters |
|---|
| | 1737 | { |
|---|
| | 1738 | interface I_3 { void test(int, in int, out int, ref int, lazy int); } |
|---|
| | 1739 | auto o = new AutoImplement!I_3; |
|---|
| | 1740 | } |
|---|
| | 1741 | // use of user-defined type |
|---|
| | 1742 | { |
|---|
| | 1743 | typedef int MyInt; |
|---|
| | 1744 | interface I_4 { MyInt test(); } |
|---|
| | 1745 | auto o = new AutoImplement!I_4; |
|---|
| | 1746 | } |
|---|
| | 1747 | // overloads |
|---|
| | 1748 | { |
|---|
| | 1749 | interface I_5 |
|---|
| | 1750 | { |
|---|
| | 1751 | void test(string); |
|---|
| | 1752 | real test(real); |
|---|
| | 1753 | int test(); |
|---|
| | 1754 | int test() @property; // ? |
|---|
| | 1755 | } |
|---|
| | 1756 | auto o = new AutoImplement!I_5; |
|---|
| | 1757 | } |
|---|
| | 1758 | // constructor forwarding |
|---|
| | 1759 | { |
|---|
| | 1760 | static class C_6 |
|---|
| | 1761 | { |
|---|
| | 1762 | this(int n) { assert(n == 42); } |
|---|
| | 1763 | this(string s) { assert(s == "Deeee"); } |
|---|
| | 1764 | this(...) {} |
|---|
| | 1765 | } |
|---|
| | 1766 | auto o1 = new AutoImplement!C_6(42); |
|---|
| | 1767 | auto o2 = new AutoImplement!C_6("Deeee"); |
|---|
| | 1768 | auto o3 = new AutoImplement!C_6(1, 2, 3, 4); |
|---|
| | 1769 | } |
|---|
| | 1770 | /+ // deep inheritance |
|---|
| | 1771 | { |
|---|
| | 1772 | // XXX [BUG 2525,3525] |
|---|
| | 1773 | // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic() |
|---|
| | 1774 | interface I { void foo(); } |
|---|
| | 1775 | interface J : I {} |
|---|
| | 1776 | interface K : J {} |
|---|
| | 1777 | static abstract class C_8 : K {} |
|---|
| | 1778 | auto o = new AutoImplement!C_8; |
|---|
| | 1779 | } +/ |
|---|
| | 1780 | // doc example |
|---|
| | 1781 | { |
|---|
| | 1782 | static class Base |
|---|
| | 1783 | { |
|---|
| | 1784 | int m_value; |
|---|
| | 1785 | this(int v) { m_value = v; } |
|---|
| | 1786 | int value() @property { return m_value; } |
|---|
| | 1787 | |
|---|
| | 1788 | abstract real realValue() @property; |
|---|
| | 1789 | abstract void doSomething(); |
|---|
| | 1790 | } |
|---|
| | 1791 | |
|---|
| | 1792 | auto obj = new AutoImplement!Base(42); |
|---|
| | 1793 | assert(obj.value == 42); |
|---|
| | 1794 | |
|---|
| | 1795 | assert(obj.realValue !<>= 0); // NaN |
|---|
| | 1796 | obj.doSomething(); |
|---|
| | 1797 | } |
|---|
| | 1798 | } |
|---|
| | 1799 | |
|---|
| | 1800 | |
|---|
| | 1801 | /** |
|---|
| | 1802 | The default $(EM how)-policy for $(D AutoImplement). Every generated function |
|---|
| | 1803 | returns the default value without doing anything. |
|---|
| | 1804 | */ |
|---|
| | 1805 | template generateEmptyFunction(C, func.../+[BUG 4217]+/) |
|---|
| | 1806 | { |
|---|
| | 1807 | static if (is(ReturnType!(func) == void)) |
|---|
| | 1808 | enum string generateEmptyFunction = q{ |
|---|
| | 1809 | }; |
|---|
| | 1810 | else static if (functionAttributes!(func) & FunctionAttribute.REF) |
|---|
| | 1811 | enum string generateEmptyFunction = q{ |
|---|
| | 1812 | static typeof(return) dummy; |
|---|
| | 1813 | return dummy; |
|---|
| | 1814 | }; |
|---|
| | 1815 | else |
|---|
| | 1816 | enum string generateEmptyFunction = q{ |
|---|
| | 1817 | return typeof(return).init; |
|---|
| | 1818 | }; |
|---|
| | 1819 | } |
|---|
| | 1820 | |
|---|
| | 1821 | |
|---|
| | 1822 | /** |
|---|
| | 1823 | A $(EM how)-policy for $(D AutoImplement). Every generated function fails with |
|---|
| | 1824 | $(D AssertError) and does never return. Useful for trapping use of |
|---|
| | 1825 | not-yet-implemented functions. |
|---|
| | 1826 | |
|---|
| | 1827 | Example: |
|---|
| | 1828 | -------------------- |
|---|
| | 1829 | class C |
|---|
| | 1830 | { |
|---|
| | 1831 | abstract void notYetImplemented(); |
|---|
| | 1832 | } |
|---|
| | 1833 | |
|---|
| | 1834 | void main() |
|---|
| | 1835 | { |
|---|
| | 1836 | auto obj = new AutoImplement!(C, generateAssertTrap); |
|---|
| | 1837 | obj.notYetImplemented(); // throws AssertError |
|---|
| | 1838 | } |
|---|
| | 1839 | -------------------- |
|---|
| | 1840 | */ |
|---|
| | 1841 | template generateAssertTrap(C, func.../+[BUG 4217]+/) |
|---|
| | 1842 | { |
|---|
| | 1843 | enum string generateAssertTrap = |
|---|
| | 1844 | `assert(0, "` ~ (C.stringof ~ "." ~ __traits(identifier, func)) |
|---|
| | 1845 | ~ ` is not implemented");`; |
|---|
| | 1846 | } |
|---|
| | 1847 | |
|---|
| | 1848 | unittest // doc example |
|---|
| | 1849 | { |
|---|
| | 1850 | static class C |
|---|
| | 1851 | { |
|---|
| | 1852 | abstract void notYetImplemented(); |
|---|
| | 1853 | } |
|---|
| | 1854 | |
|---|
| | 1855 | auto o = new AutoImplement!(C, generateAssertTrap); |
|---|
| | 1856 | try |
|---|
| | 1857 | { |
|---|
| | 1858 | o.notYetImplemented(); |
|---|
| | 1859 | assert(0); |
|---|
| | 1860 | } |
|---|
| | 1861 | catch (Error e) {} |
|---|
| | 1862 | } |
|---|
| | 1863 | |
|---|
| | 1864 | |
|---|
| | 1865 | /* |
|---|
| | 1866 | Used by MemberFunctionGenerator. |
|---|
| | 1867 | */ |
|---|
| | 1868 | private template OverloadSet(string nam, T...) |
|---|
| | 1869 | { |
|---|
| | 1870 | enum string name = nam; |
|---|
| | 1871 | alias T contents; |
|---|
| | 1872 | } |
|---|
| | 1873 | |
|---|
| | 1874 | /* |
|---|
| | 1875 | Used by MemberFunctionGenerator. |
|---|
| | 1876 | */ |
|---|
| | 1877 | private template FuncInfo(alias func, /+[BUG 4217 ?]+/ T = typeof(&func)) |
|---|
| | 1878 | { |
|---|
| | 1879 | alias ReturnType!(T) RT; |
|---|
| | 1880 | alias ParameterTypeTuple!(T) PT; |
|---|
| | 1881 | } |
|---|
| | 1882 | |
|---|
| | 1883 | /* |
|---|
| | 1884 | General-purpose member function generator. |
|---|
| | 1885 | */ |
|---|
| | 1886 | private template MemberFunctionGenerator(alias Policy) |
|---|
| | 1887 | { |
|---|
| | 1888 | private static: |
|---|
| | 1889 | //mixin Policy; // can't |
|---|
| | 1890 | |
|---|
| | 1891 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1892 | // Internal stuffs |
|---|
| | 1893 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1894 | |
|---|
| | 1895 | enum CONSTRUCTOR_NAME = "__ctor"; |
|---|
| | 1896 | enum WITH_BASE_CLASS = __traits(compiles, Policy.BASE_CLASS_ID); |
|---|
| | 1897 | |
|---|
| | 1898 | // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach. |
|---|
| | 1899 | template CountUp(size_t n) |
|---|
| | 1900 | { |
|---|
| | 1901 | static if (n > 0) |
|---|
| | 1902 | alias TypeTuple!(CountUp!(n - 1), n - 1) CountUp; |
|---|
| | 1903 | else |
|---|
| | 1904 | alias TypeTuple!() CountUp; |
|---|
| | 1905 | } |
|---|
| | 1906 | |
|---|
| | 1907 | |
|---|
| | 1908 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1909 | // Code generator |
|---|
| | 1910 | //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// |
|---|
| | 1911 | |
|---|
| | 1912 | /* |
|---|
| | 1913 | * Runs through all the target overload sets and generates D code which |
|---|
| | 1914 | * implements all the functions in the overload sets. |
|---|
| | 1915 | */ |
|---|
| | 1916 | public string generateCode(overloads...)() @property |
|---|
| | 1917 | { |
|---|
| | 1918 | string code = ""; |
|---|
| | 1919 | |
|---|
| | 1920 | // run through all the overload sets |
|---|
| | 1921 | foreach (i_; CountUp!(0 + overloads.length)) // workaround |
|---|
| | 1922 | { |
|---|
| | 1923 | enum i = 0 + i_; // workaround |
|---|
| | 1924 | alias overloads[i] oset; |
|---|
| | 1925 | |
|---|
| | 1926 | code ~= generateCodeForOverloadSet!(oset); |
|---|
| | 1927 | |
|---|
| | 1928 | static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME) |
|---|
| | 1929 | { |
|---|
| | 1930 | // The generated function declarations may hide existing ones |
|---|
| | 1931 | // in the base class (cf. HiddenFuncError), so we put an alias |
|---|
| | 1932 | // declaration here to reveal possible hidden functions. |
|---|
| | 1933 | code ~= Format!("alias %s.%s %s;\n", |
|---|
| | 1934 | Policy.BASE_CLASS_ID, // [BUG 2540] super. |
|---|
| | 1935 | oset.name, oset.name ); |
|---|
| | 1936 | } |
|---|
| | 1937 | } |
|---|
| | 1938 | return code; |
|---|
| | 1939 | } |
|---|
| | 1940 | |
|---|
| | 1941 | // handle each overload set |
|---|
| | 1942 | private string generateCodeForOverloadSet(alias oset)() @property |
|---|
| | 1943 | { |
|---|
| | 1944 | string code = ""; |
|---|
| | 1945 | |
|---|
| | 1946 | foreach (i_; CountUp!(0 + oset.contents.length)) // workaround |
|---|
| | 1947 | { |
|---|
| | 1948 | enum i = 0 + i_; // workaround |
|---|
| | 1949 | code ~= generateFunction!( |
|---|
| | 1950 | oset.contents[i], Policy.FUNCINFO_ID!(oset.name, i)) ~ "\n"; |
|---|
| | 1951 | } |
|---|
| | 1952 | return code; |
|---|
| | 1953 | } |
|---|
| | 1954 | |
|---|
| | 1955 | /* |
|---|
| | 1956 | * Returns D code which implements the function func. This function |
|---|
| | 1957 | * actually generates only the declarator part; the function body part is |
|---|
| | 1958 | * generated by the functionGenerator() policy. |
|---|
| | 1959 | */ |
|---|
| | 1960 | //private string generateFunction(alias func, string myFuncInfo)() @property |
|---|
| | 1961 | private string generateFunction(args_.../+[BUG 4217]+/)() @property |
|---|
| | 1962 | { |
|---|
| | 1963 | alias args_[0..1] func; enum myFuncInfo = args_[1]; |
|---|
| | 1964 | |
|---|
| | 1965 | enum name = __traits(identifier, func); |
|---|
| | 1966 | enum isCtor = (name == CONSTRUCTOR_NAME); |
|---|
| | 1967 | |
|---|
| | 1968 | string code; // the result |
|---|
| | 1969 | |
|---|
| | 1970 | /*** Function Declarator ***/ |
|---|
| | 1971 | { |
|---|
| | 1972 | alias FunctionAttribute FA; |
|---|
| | 1973 | enum atts = functionAttributes!(func); |
|---|
| | 1974 | enum realName = isCtor ? "this" : name; |
|---|
| | 1975 | |
|---|
| | 1976 | /* Just for the sake of Format!(...). */ |
|---|
| | 1977 | static string make_postAtts() |
|---|
| | 1978 | { |
|---|
| | 1979 | string poatts = ""; |
|---|
| | 1980 | if (atts & FA.PURE ) poatts ~= " pure"; |
|---|
| | 1981 | if (atts & FA.NOTHROW ) poatts ~= " nothrow"; |
|---|
| | 1982 | if (atts & FA.PROPERTY) poatts ~= " @property"; |
|---|
| | 1983 | if (atts & FA.SAFE ) poatts ~= " @safe"; |
|---|
| | 1984 | if (atts & FA.TRUSTED ) poatts ~= " @trusted"; |
|---|
| | 1985 | return poatts; |
|---|
| | 1986 | } |
|---|
| | 1987 | enum postAtts = make_postAtts(); |
|---|
| | 1988 | |
|---|
| | 1989 | static string make_returnType() |
|---|
| | 1990 | { |
|---|
| | 1991 | string rtype = ""; |
|---|
| | 1992 | |
|---|
| | 1993 | if (!isCtor) |
|---|
| | 1994 | { |
|---|
| | 1995 | if (atts & FA.REF) rtype ~= "ret "; |
|---|
| | 1996 | rtype ~= myFuncInfo ~ ".RT"; |
|---|
| | 1997 | } |
|---|
| | 1998 | return rtype; |
|---|
| | 1999 | } |
|---|
| | 2000 | enum returnType = make_returnType(); |
|---|
| | 2001 | |
|---|
| | 2002 | // |
|---|
| | 2003 | code ~= Format!("extern(%s) %s %s(%s) %s\n", |
|---|
| | 2004 | functionLinkage!(func), |
|---|
| | 2005 | returnType, |
|---|
| | 2006 | realName, |
|---|
| | 2007 | ""~generateParameters!(func, myFuncInfo), |
|---|
| | 2008 | postAtts ); |
|---|
| | 2009 | } |
|---|
| | 2010 | |
|---|
| | 2011 | /*** Function Body ***/ |
|---|
| | 2012 | code ~= "{\n"; |
|---|
| | 2013 | { |
|---|
| | 2014 | enum nparams = ParameterTypeTuple!(func).length; |
|---|
| | 2015 | |
|---|
| | 2016 | /* Declare keywords: args, self and parent. */ |
|---|
| | 2017 | string preamble; |
|---|
| | 2018 | |
|---|
| | 2019 | preamble ~= "alias TypeTuple!(" ~ enumerateParameters!(nparams) ~ ") args;\n"; |
|---|
| | 2020 | if (!isCtor) |
|---|
| | 2021 | { |
|---|
| | 2022 | preamble ~= "alias " ~ name ~ " self;\n"; |
|---|
| | 2023 | if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func)) |
|---|
| | 2024 | //preamble ~= "alias super." ~ name ~ " parent;\n"; // [BUG 2540] |
|---|
| | 2025 | preamble ~= "auto parent = &super." ~ name ~ ";\n"; |
|---|
| | 2026 | } |
|---|
| | 2027 | |
|---|
| | 2028 | // |
|---|
| | 2029 | code ~= preamble; |
|---|
| | 2030 | code ~= Policy.generateFunctionBody!(func); |
|---|
| | 2031 | } |
|---|
| | 2032 | code ~= "}"; |
|---|
| | 2033 | |
|---|
| | 2034 | return code; |
|---|
| | 2035 | } |
|---|
| | 2036 | |
|---|
| | 2037 | /* |
|---|
| | 2038 | * Returns D code which declares function parameters. |
|---|
| | 2039 | * "ref int a0, real a1, ..." |
|---|
| | 2040 | */ |
|---|
| | 2041 | //private string generateParameters(alias func, string myFuncInfo)() @property |
|---|
| | 2042 | private string generateParameters(args_.../+[BUG 4217]+/)() @property |
|---|
| | 2043 | { |
|---|
| | 2044 | alias args_[0..1] func; enum myFuncInfo = args_[1]; |
|---|
| | 2045 | |
|---|
| | 2046 | alias ParameterStorageClass STC; |
|---|
| | 2047 | alias ParameterStorageClassTuple!(func) stcs; |
|---|
| | 2048 | enum nparams = stcs.length; |
|---|
| | 2049 | |
|---|
| | 2050 | string params = ""; // the result |
|---|
| | 2051 | |
|---|
| | 2052 | foreach (i, stc; stcs) |
|---|
| | 2053 | { |
|---|
| | 2054 | if (i > 0) params ~= ", "; |
|---|
| | 2055 | |
|---|
| | 2056 | // Parameter storage classes. |
|---|
| | 2057 | if (stc & STC.SCOPE) params ~= "scope "; |
|---|
| | 2058 | if (stc & STC.OUT ) params ~= "out "; |
|---|
| | 2059 | if (stc & STC.REF ) params ~= "ref "; |
|---|
| | 2060 | if (stc & STC.LAZY ) params ~= "lazy "; |
|---|
| | 2061 | |
|---|
| | 2062 | // Take parameter type from the FuncInfo. |
|---|
| | 2063 | params ~= myFuncInfo ~ ".PT[" ~ toStringNow!(i) ~ "]"; |
|---|
| | 2064 | |
|---|
| | 2065 | // Declare a parameter variable. |
|---|
| | 2066 | params ~= " " ~ Policy.PARAMETER_VARIABLE_ID!(i); |
|---|
| | 2067 | } |
|---|
| | 2068 | |
|---|
| | 2069 | // Add some ellipsis part if needed. |
|---|
| | 2070 | final switch (variadicFunctionStyle!(func)) |
|---|
| | 2071 | { |
|---|
| | 2072 | case Variadic.NO: |
|---|
| | 2073 | break; |
|---|
| | 2074 | |
|---|
| | 2075 | case Variadic.C, Variadic.D: |
|---|
| | 2076 | // (...) or (a, b, ...) |
|---|
| | 2077 | params ~= (nparams == 0) ? "..." : ", ..."; |
|---|
| | 2078 | break; |
|---|
| | 2079 | |
|---|
| | 2080 | case Variadic.TYPESAFE: |
|---|
| | 2081 | params ~= " ..."; |
|---|
| | 2082 | break; |
|---|
| | 2083 | } |
|---|
| | 2084 | |
|---|
| | 2085 | return params; |
|---|
| | 2086 | } |
|---|
| | 2087 | |
|---|
| | 2088 | // Returns D code which enumerates n parameter variables using comma as the |
|---|
| | 2089 | // separator. "a0, a1, a2, a3" |
|---|
| | 2090 | private string enumerateParameters(size_t n)() @property |
|---|
| | 2091 | { |
|---|
| | 2092 | string params = ""; |
|---|
| | 2093 | |
|---|
| | 2094 | foreach (i_; CountUp!(n)) |
|---|
| | 2095 | { |
|---|
| | 2096 | enum i = 0 + i_; // workaround |
|---|
| | 2097 | if (i > 0) params ~= ", "; |
|---|
| | 2098 | params ~= Policy.PARAMETER_VARIABLE_ID!(i); |
|---|
| | 2099 | } |
|---|
| | 2100 | return params; |
|---|
| | 2101 | } |
|---|
| | 2102 | } |
|---|