diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-03 14:18:07 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-03 14:18:07 -0300 |
commit | 4d46289331395a845c5de1f6c0e0fe873c50db4f (patch) | |
tree | 96649174d3c13830549ad026af0133e0b789d411 /lparser.c | |
parent | 8eca21c2e85625390a2a3b08c231e75e315980b0 (diff) | |
download | lua-4d46289331395a845c5de1f6c0e0fe873c50db4f.tar.gz lua-4d46289331395a845c5de1f6c0e0fe873c50db4f.tar.bz2 lua-4d46289331395a845c5de1f6c0e0fe873c50db4f.zip |
Local attributes can be used in list of local variables
The syntax for local attributes ('const'/'toclose') was unified with
the regular syntax for local variables, so that we can have variables
with attributes in local definitions with multiple names; for instance:
local <toclose> f, <const> err = io.open(fname)
This new syntax does not implement constant propagation, yet.
This commit also has some small improvements to the manual.
Diffstat (limited to 'lparser.c')
-rw-r--r-- | lparser.c | 90 |
1 files changed, 41 insertions, 49 deletions
@@ -1656,13 +1656,50 @@ static void localfunc (LexState *ls) { | |||
1656 | } | 1656 | } |
1657 | 1657 | ||
1658 | 1658 | ||
1659 | static void commonlocalstat (LexState *ls) { | 1659 | static int getlocalattribute (LexState *ls) { |
1660 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ | 1660 | /* ATTRIB -> ['<' Name '>'] */ |
1661 | if (testnext(ls, '<')) { | ||
1662 | const char *attr = getstr(str_checkname(ls)); | ||
1663 | checknext(ls, '>'); | ||
1664 | if (strcmp(attr, "const") == 0) | ||
1665 | return 1; /* read-only variable */ | ||
1666 | else if (strcmp(attr, "toclose") == 0) | ||
1667 | return 2; /* to-be-closed variable */ | ||
1668 | else | ||
1669 | luaK_semerror(ls, | ||
1670 | luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); | ||
1671 | } | ||
1672 | return 0; | ||
1673 | } | ||
1674 | |||
1675 | |||
1676 | static void checktoclose (LexState *ls, int toclose) { | ||
1677 | if (toclose != -1) { /* is there a to-be-closed variable? */ | ||
1678 | FuncState *fs = ls->fs; | ||
1679 | markupval(fs, fs->nactvar + toclose + 1); | ||
1680 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | ||
1681 | luaK_codeABC(fs, OP_TBC, fs->nactvar + toclose, 0, 0); | ||
1682 | } | ||
1683 | } | ||
1684 | |||
1685 | |||
1686 | static void localstat (LexState *ls) { | ||
1687 | /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */ | ||
1688 | int toclose = -1; /* index of to-be-closed variable (if any) */ | ||
1661 | int nvars = 0; | 1689 | int nvars = 0; |
1662 | int nexps; | 1690 | int nexps; |
1663 | expdesc e; | 1691 | expdesc e; |
1664 | do { | 1692 | do { |
1665 | new_localvar(ls, str_checkname(ls)); | 1693 | int kind = getlocalattribute(ls); |
1694 | Vardesc *var = new_localvar(ls, str_checkname(ls)); | ||
1695 | if (kind != 0) { /* is there an attribute? */ | ||
1696 | var->ro = 1; /* all attributes make variable read-only */ | ||
1697 | if (kind == 2) { /* to-be-closed? */ | ||
1698 | if (toclose != -1) /* one already present? */ | ||
1699 | luaK_semerror(ls, "multiple to-be-closed variables in local list"); | ||
1700 | toclose = nvars; | ||
1701 | } | ||
1702 | } | ||
1666 | nvars++; | 1703 | nvars++; |
1667 | } while (testnext(ls, ',')); | 1704 | } while (testnext(ls, ',')); |
1668 | if (testnext(ls, '=')) | 1705 | if (testnext(ls, '=')) |
@@ -1672,56 +1709,11 @@ static void commonlocalstat (LexState *ls) { | |||
1672 | nexps = 0; | 1709 | nexps = 0; |
1673 | } | 1710 | } |
1674 | adjust_assign(ls, nvars, nexps, &e); | 1711 | adjust_assign(ls, nvars, nexps, &e); |
1712 | checktoclose(ls, toclose); | ||
1675 | adjustlocalvars(ls, nvars); | 1713 | adjustlocalvars(ls, nvars); |
1676 | } | 1714 | } |
1677 | 1715 | ||
1678 | 1716 | ||
1679 | static void tocloselocalstat (LexState *ls, Vardesc *var) { | ||
1680 | FuncState *fs = ls->fs; | ||
1681 | var->ro = 1; /* to-be-closed variables are always read-only */ | ||
1682 | markupval(fs, fs->nactvar + 1); | ||
1683 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | ||
1684 | luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0); | ||
1685 | } | ||
1686 | |||
1687 | |||
1688 | static void checkattrib (LexState *ls, TString *attr, Vardesc *var) { | ||
1689 | if (strcmp(getstr(attr), "const") == 0) | ||
1690 | var->ro = 1; /* set variable as read-only */ | ||
1691 | else if (strcmp(getstr(attr), "toclose") == 0) | ||
1692 | tocloselocalstat(ls, var); | ||
1693 | else | ||
1694 | luaK_semerror(ls, | ||
1695 | luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); | ||
1696 | } | ||
1697 | |||
1698 | |||
1699 | static void attriblocalstat (LexState *ls) { | ||
1700 | FuncState *fs = ls->fs; | ||
1701 | Vardesc *var; | ||
1702 | expdesc e; | ||
1703 | TString *attr = str_checkname(ls); | ||
1704 | testnext(ls, '>'); | ||
1705 | var = new_localvar(ls, str_checkname(ls)); | ||
1706 | checknext(ls, '='); | ||
1707 | expr(ls, &e); | ||
1708 | checkattrib(ls, attr, var); | ||
1709 | luaK_tonumeral(fs, &e, &var->val); | ||
1710 | luaK_exp2nextreg(fs, &e); | ||
1711 | adjustlocalvars(ls, 1); | ||
1712 | } | ||
1713 | |||
1714 | |||
1715 | static void localstat (LexState *ls) { | ||
1716 | /* stat -> LOCAL NAME {',' NAME} ['=' explist] | ||
1717 | | LOCAL *toclose NAME '=' exp */ | ||
1718 | if (testnext(ls, '<')) | ||
1719 | attriblocalstat(ls); | ||
1720 | else | ||
1721 | commonlocalstat(ls); | ||
1722 | } | ||
1723 | |||
1724 | |||
1725 | static int funcname (LexState *ls, expdesc *v) { | 1717 | static int funcname (LexState *ls, expdesc *v) { |
1726 | /* funcname -> NAME {fieldsel} [':' NAME] */ | 1718 | /* funcname -> NAME {fieldsel} [':' NAME] */ |
1727 | int ismethod = 0; | 1719 | int ismethod = 0; |