Merge branch '1.12' of https://github.com/wesnoth/wesnoth into 1.12
Conflicts: RELEASE_NOTES
This commit is contained in:
commit
0416872fb5
62 changed files with 1897 additions and 1432 deletions
|
@ -41,13 +41,24 @@ SDL_mixer 1.2.12
|
|||
|
||||
For both scons and cmake, the first two may be disabled (and the old code used, rolling back results of previous section) by turning off the "enable boost filesystem" flag. For cmake, the third requirement may also be removed, reducing SDL_mixer dependency to 1.2.0, by using the ENABLE_PANDORA flag.
|
||||
|
||||
For those of you compiling Wesnoth on OS X using Xcode, this means that you need to download a new version of wesnoth_compile_mac_1.11.zip.
|
||||
Wesnoth OS X builds and release packages do not use the new dependencies in order to retain support of OS X Leopard (10.5) for the Wesnoth 1.12 series. Unicode character support does not seem to be a problem on OS X.
|
||||
[/section]
|
||||
|
||||
[section="Example section 1"]
|
||||
Example contents 1.
|
||||
[/section]
|
||||
|
||||
[rasection="[i]Legend of Wesmere[/i]: Bug fixes”]Remaining known issues affecting [i]Legend of Wesmere[/i] (single player mode) have been fixed:
|
||||
|
||||
[list][*]“Ka’lian under attack”: fixed more issues due to new map size.
|
||||
[*]“Ka’lian under attack”: fixed two issues with fog. This fixes bug [bug]22880[/bug].
|
||||
[*]“Elves Last Stand”: fixed not all elvish leaders being able to recruit.
|
||||
[*]“Elves Last Stand”: fixed bugs in Olurf and Olurf's party arrival.
|
||||
[*]“Bounty Hunters”: fixed several coordinate issues due to new map size.
|
||||
[*]“Cliffs of Thoria”: fixed so that yetis can be seen moving in hole in fog.
|
||||
[*]Fixed player team name in several scenarios.
|
||||
[*]Fixed player side carryover in several scenarios.[/list][/rasection]
|
||||
|
||||
==========
|
||||
KNOWN BUGS
|
||||
==========
|
||||
|
|
29
changelog
29
changelog
|
@ -1,11 +1,24 @@
|
|||
Version 1.11.18+dev:
|
||||
* Campaigns:
|
||||
* Legend of Wesmere:
|
||||
* Ka’lian under attack: fixed more issues due to new map size.
|
||||
* Ka’lian under attack: fixed two issues with fog. This fixes bug #22880.
|
||||
* Elves Last Stand: fixed not all elvish leaders being able to recruit.
|
||||
* Elves Last Stand: fixed bugs in Olurf and Olurf's party arrival.
|
||||
* Bounty Hunters: fixed several coordinate issues due to new map size.
|
||||
* Cliffs of Thoria: fixed so that yetis can be seen moving in hole in fog.
|
||||
* Fixed player team name in several scenarios.
|
||||
* Fixed player side carryover in several scenarios.
|
||||
* Language and i18n:
|
||||
* Updated translations: Galician, German, Italian, Portuguese,
|
||||
Scottish Gaelic, Slovak, Spanish
|
||||
* Lua API:
|
||||
* Upgraded Lua to version 5.2.3.
|
||||
* Miscellaneous and bug fixes:
|
||||
* For compiling Wesnoth on OS X using Xcode, a new version of
|
||||
wesnoth_compile_mac_1.11.zip is now required.
|
||||
* Micro AIs: only display on-screen error messages when in debug mode
|
||||
* WML engine:
|
||||
* Fixed a bug that prevented [animate_unit] from displaying death or victory
|
||||
animations for those units that filter them based on weapon (eg. Wose)
|
||||
|
||||
Version 1.11.18:
|
||||
* Add-ons server:
|
||||
|
@ -13,6 +26,18 @@ Version 1.11.18:
|
|||
* Campaigns:
|
||||
* Eastern Invasion:
|
||||
* Updated maps for scenario 14, 16 and 17b.
|
||||
* Legend of Wesmere:
|
||||
* Fixed broken sides configuration and starting locations in several
|
||||
scenarios.
|
||||
* The Uprooting: fixed Arkildur not appearing in multiplayer mode.
|
||||
* Ka’lian under attack: fixed units and labels offset due to different map
|
||||
sizes after Kalenz and Landar appear (bug #22073).
|
||||
* Bounty Hunters: fixed Olurf being unable to recruit.
|
||||
* Human Alliance: completely redone and rebalanced. This fixes bug #21941,
|
||||
implements FR #16600, and addresses comments made in the feedback topic
|
||||
on the forums.
|
||||
* Chapter 4 is now available in multiplayer mode again.
|
||||
* Minor (mostly cosmetic) changes to several maps.
|
||||
* Under the Burning Suns:
|
||||
* Fixed recruited Desert Archers being always male.
|
||||
* Fixed malformed rand range errors during AI turns on medium difficulty
|
||||
|
|
|
@ -99,7 +99,7 @@ Chapter Two"
|
|||
[side]
|
||||
#Cleodil's side
|
||||
side=3
|
||||
#no_leader=yes
|
||||
no_leader=yes
|
||||
#ifdef MULTIPLAYER
|
||||
{CLEODIL}
|
||||
type=Elvish Shyde
|
||||
|
@ -301,22 +301,7 @@ Chapter Two"
|
|||
|
||||
|
||||
#ifdef MULTIPLAYER
|
||||
[recall]
|
||||
type=Elvish Ranger, Elvish Avenger
|
||||
role=liberator
|
||||
x=23
|
||||
y=24
|
||||
[/recall]
|
||||
[if]
|
||||
[not]
|
||||
[have_unit]
|
||||
role=liberator
|
||||
[/have_unit]
|
||||
[/not]
|
||||
[then]
|
||||
{UNIT 1 (Elvish Ranger) 23 24 (role=liberator)}
|
||||
[/then]
|
||||
[/if]
|
||||
{UNIT 3 (Elvish Ranger) 23 24 (role=liberator)}
|
||||
#else
|
||||
[allow_extra_recruit]
|
||||
id=Kalenz,Landar
|
||||
|
@ -383,7 +368,7 @@ Chapter Two"
|
|||
# wmllint: who CLEODIL is Cleodil
|
||||
{CLEODIL}
|
||||
#ifdef MULTIPLAYER
|
||||
side=5
|
||||
side=3
|
||||
#else
|
||||
side=1
|
||||
#endif
|
||||
|
@ -397,7 +382,7 @@ Chapter Two"
|
|||
[unit]
|
||||
{LARIL}
|
||||
#ifdef MULTIPLAYER
|
||||
side=5
|
||||
side=3
|
||||
#else
|
||||
side=1
|
||||
#endif
|
||||
|
@ -406,7 +391,7 @@ Chapter Two"
|
|||
[unit]
|
||||
{TAMERIL_ISIMERIL}
|
||||
#ifdef MULTIPLAYER
|
||||
side=5
|
||||
side=3
|
||||
#else
|
||||
side=1
|
||||
#endif
|
||||
|
|
|
@ -75,12 +75,12 @@
|
|||
user_team_name= _ "Player"
|
||||
|
||||
[unit]
|
||||
{KALENZ}
|
||||
{KALENZ}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=46
|
||||
y=21
|
||||
[/unit]
|
||||
|
||||
|
||||
#ifndef MULTIPLAYER
|
||||
{PLAYER_GOLD}
|
||||
[unit]
|
||||
|
@ -131,7 +131,7 @@
|
|||
type=Elvish Ranger
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=45
|
||||
y=35
|
||||
y=35
|
||||
[/unit]
|
||||
#else
|
||||
hidden=yes
|
||||
|
@ -186,11 +186,11 @@
|
|||
#endif
|
||||
|
||||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
user_team_name= _ "Player"
|
||||
|
||||
[unit]
|
||||
# wmllint: recognize Galtrid
|
||||
{GALTRID}
|
||||
{GALTRID}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=33
|
||||
y=32
|
||||
|
@ -200,12 +200,14 @@
|
|||
[unit]
|
||||
# wmllint: recognize El_Isomithir
|
||||
{EL_ISOMITHIR}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=29
|
||||
y=32
|
||||
[/unit]
|
||||
[unit]
|
||||
# wmllint: recognize Eradion
|
||||
{ERADION}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=7
|
||||
y=36
|
||||
[/unit]
|
||||
|
@ -248,7 +250,7 @@
|
|||
controller=null
|
||||
#endif
|
||||
[/side]
|
||||
|
||||
|
||||
|
||||
[event]
|
||||
name=prestart
|
||||
|
@ -516,11 +518,16 @@
|
|||
side=8
|
||||
#endif
|
||||
{OLURF}
|
||||
canrecruit=yes
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[/unit]
|
||||
|
||||
{OLURF_PARTY}
|
||||
#ifndef MULTIPLAYER
|
||||
{OLURF_PARTY 1}
|
||||
#else
|
||||
{OLURF_PARTY 8}
|
||||
#endif
|
||||
|
||||
####ifndef MULTIPLAYER
|
||||
#### {MODIFY_UNIT (side=8) side 1}
|
||||
|
|
|
@ -119,7 +119,7 @@ Chapter Four"
|
|||
no_leader=yes
|
||||
|
||||
[unit]
|
||||
id=Aldar
|
||||
id=Aldar
|
||||
type=General
|
||||
name= _ "Aldar"
|
||||
profile="portraits/aldar.png"
|
||||
|
@ -176,11 +176,11 @@ Chapter Four"
|
|||
#ifdef EASY
|
||||
extra_recruit=Orcish Grunt, Orcish Assassin, Orcish Crossbowman, Goblin Pillager, Goblin Knight
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NORMAL
|
||||
extra_recruit=Orcish Archer, Orcish Assassin, Orcish Grunt, Wolf Rider, Orcish Crossbowman, Goblin Pillager, Goblin Knight, Orcish Slayer, Orcish Warrior, Goblin Spearman
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HARD
|
||||
extra_recruit=Orcish Archer, Orcish Assassin, Orcish Grunt, Wolf Rider, Orcish Crossbowman, Orcish Warrior, Goblin Knight, Goblin Pillager, Orcish Slayer, Goblin Spearman, Goblin Impaler, Goblin Rouser, Direwolf Rider
|
||||
#endif
|
||||
|
@ -190,18 +190,18 @@ Chapter Four"
|
|||
type=Orcish Warlord
|
||||
id=Tan-Grub
|
||||
name=_ "Tan-Grub"
|
||||
profile="portraits/orcs/transparent/warlord.png"
|
||||
profile="portraits/orcs/transparent/warlord.png"
|
||||
canrecruit=yes
|
||||
x=10
|
||||
y=33
|
||||
#ifdef EASY
|
||||
extra_recruit=Orcish Grunt, Orcish Assassin, Orcish Crossbowman, Goblin Pillager, Goblin Knight
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NORMAL
|
||||
extra_recruit=Orcish Archer, Orcish Assassin, Orcish Grunt, Wolf Rider, Orcish Crossbowman, Goblin Pillager, Goblin Knight, Orcish Slayer, Orcish Warrior, Goblin Spearman
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HARD
|
||||
extra_recruit=Orcish Archer, Orcish Assassin, Orcish Grunt, Wolf Rider, Orcish Crossbowman, Orcish Warrior, Goblin Knight, Goblin Pillager, Orcish Slayer, Goblin Spearman, Goblin Impaler, Goblin Rouser, Direwolf Rider
|
||||
#endif
|
||||
|
@ -412,7 +412,7 @@ Chapter Four"
|
|||
{PLAYABLE}
|
||||
|
||||
[unit]
|
||||
{LANDAR}
|
||||
{LANDAR}
|
||||
x=27
|
||||
y=12
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
|
@ -427,7 +427,7 @@ Chapter Four"
|
|||
no_leader=yes
|
||||
|
||||
[unit]
|
||||
{OLURF}
|
||||
{OLURF}
|
||||
x=36
|
||||
y=10
|
||||
[/unit]
|
||||
|
@ -447,7 +447,7 @@ Chapter Four"
|
|||
{PLAYABLE}
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{CLEODIL}
|
||||
{CLEODIL}
|
||||
x=25
|
||||
y=13
|
||||
[/unit]
|
||||
|
@ -466,11 +466,11 @@ Chapter Four"
|
|||
{PLAYABLE}
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{EL_ISOMITHIR}
|
||||
{EL_ISOMITHIR}
|
||||
x=13
|
||||
y=15
|
||||
[/unit]
|
||||
|
||||
|
||||
{MULTIPLAYER_GOLD}
|
||||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
|
@ -485,7 +485,7 @@ Chapter Four"
|
|||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{ERADION}
|
||||
{ERADION}
|
||||
x=15
|
||||
y=15
|
||||
[/unit]
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#wmllint: validate-off
|
||||
[side]
|
||||
{KALENZ}
|
||||
user_team_name= _ "Player"
|
||||
controller=human
|
||||
village_gold=0
|
||||
#This sets the income to 0
|
||||
|
|
|
@ -49,15 +49,12 @@
|
|||
|
||||
[side]
|
||||
side=1
|
||||
no_leader=yes
|
||||
controller=human
|
||||
|
||||
[unit]
|
||||
{KALENZ}
|
||||
x=46
|
||||
y=39
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
[/unit]
|
||||
{KALENZ}
|
||||
type=Elvish High Lord
|
||||
x=46
|
||||
y=39
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
|
||||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
|
@ -105,7 +102,7 @@
|
|||
{URADREDIA}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout, Elvish Shaman
|
||||
x=24
|
||||
y=7
|
||||
y=7
|
||||
[/unit]
|
||||
[/side]
|
||||
|
||||
|
@ -227,7 +224,7 @@
|
|||
no_leader=yes
|
||||
[unit]
|
||||
{LANDAR}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=20
|
||||
y=4
|
||||
[/unit]
|
||||
|
@ -236,13 +233,13 @@
|
|||
[side]
|
||||
side=7
|
||||
save_id=Olurf
|
||||
|
||||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{OLURF}
|
||||
extra_recruit=Dwarvish Fighter, Dwarvish Thunderer, Dwarvish Guardsman, Dwarvish Scout
|
||||
x=20
|
||||
y=4
|
||||
y=4
|
||||
[/unit]
|
||||
{MULTIPLAYER_GOLD}
|
||||
fog=yes
|
||||
|
@ -255,7 +252,7 @@
|
|||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{CLEODIL}
|
||||
{CLEODIL}
|
||||
extra_recruit=Elvish Shaman, Wose, Elvish Scout
|
||||
x=20
|
||||
y=4
|
||||
|
|
|
@ -84,10 +84,11 @@ Chapter Five"
|
|||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
controller=human
|
||||
save_id=Kalenz
|
||||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{KALENZ}
|
||||
{KALENZ}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=3
|
||||
y=18
|
||||
|
@ -188,11 +189,11 @@ Chapter Five"
|
|||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
|
||||
{MULTIPLAYER_GOLD}
|
||||
{MULTIPLAYER_GOLD}
|
||||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{LANDAR}
|
||||
{LANDAR}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=3
|
||||
y=18
|
||||
|
|
|
@ -54,14 +54,12 @@
|
|||
|
||||
[side]
|
||||
side=1
|
||||
no_leader=yes
|
||||
controller=human
|
||||
[unit]
|
||||
{KALENZ}
|
||||
x=11
|
||||
y=18
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
[/unit]
|
||||
{KALENZ}
|
||||
type=Elvish High Lord
|
||||
x=11
|
||||
y=18
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
|
||||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
|
@ -355,7 +353,7 @@
|
|||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{CLEODIL}
|
||||
{CLEODIL}
|
||||
extra_recruit=Elvish Shaman, Elvish Scout, Wose
|
||||
x=11
|
||||
y=18
|
||||
|
|
|
@ -41,15 +41,16 @@
|
|||
side=1
|
||||
|
||||
{PLAYABLE}
|
||||
save_id=Kalenz
|
||||
team_name=player
|
||||
user_team_name= _ "Player"
|
||||
controller=human
|
||||
|
||||
{GOLD 100 100 100}
|
||||
|
||||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{KALENZ}
|
||||
{KALENZ}
|
||||
extra_recruit=Elvish Fighter, Elvish Archer, Elvish Scout
|
||||
x=46
|
||||
y=39
|
||||
|
@ -150,10 +151,10 @@
|
|||
|
||||
[side]
|
||||
side=2
|
||||
|
||||
|
||||
no_leader=yes
|
||||
[unit]
|
||||
{URADREDIA}
|
||||
{URADREDIA}
|
||||
x=24
|
||||
y=7
|
||||
[/unit]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
user_team_name= _ "Player"
|
||||
village_gold=1
|
||||
#ifdef MULTIPLAYER
|
||||
persistence=yes
|
||||
persistent=yes
|
||||
team_lock=yes
|
||||
gold_lock=yes
|
||||
income_lock=yes
|
||||
|
@ -153,12 +153,12 @@
|
|||
[/modifications]
|
||||
#enddef
|
||||
|
||||
#define OLURF_PARTY
|
||||
#define OLURF_PARTY SIDE
|
||||
[unit]
|
||||
id=Bulrod
|
||||
name=_ "Bulrod"
|
||||
type=Dwarvish Steelclad
|
||||
side=8
|
||||
side={SIDE}
|
||||
#placement=leader
|
||||
unrenamable=yes
|
||||
x=$olurf_entry.x
|
||||
|
@ -173,7 +173,7 @@
|
|||
name=_ "Simclon"
|
||||
unrenamable=yes
|
||||
type=Dwarvish Thunderer
|
||||
side=8
|
||||
side={SIDE}
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[modifications]
|
||||
|
@ -188,7 +188,7 @@
|
|||
name=_ "Harald"
|
||||
unrenamable=yes
|
||||
type=Dwarvish Berserker
|
||||
side=8
|
||||
side={SIDE}
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[modifications]
|
||||
|
@ -203,7 +203,7 @@
|
|||
name=_ "Budrin"
|
||||
unrenamable=yes
|
||||
type=Dwarvish Berserker
|
||||
side=8
|
||||
side={SIDE}
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[modifications]
|
||||
|
@ -217,7 +217,7 @@
|
|||
name=_ "Dudan"
|
||||
unrenamable=yes
|
||||
type=Dwarvish Fighter
|
||||
side=8
|
||||
side={SIDE}
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[modifications]
|
||||
|
@ -231,7 +231,7 @@
|
|||
name=_ "Korbun"
|
||||
unrenamable=yes
|
||||
type=Dwarvish Scout
|
||||
side=8
|
||||
side={SIDE}
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[modifications]
|
||||
|
@ -246,7 +246,7 @@
|
|||
name=_ "Merhun"
|
||||
unrenamable=yes
|
||||
type=Dwarvish Berserker
|
||||
side=8
|
||||
side={SIDE}
|
||||
x=$olurf_entry.x
|
||||
y=$olurf_entry.y
|
||||
[modifications]
|
||||
|
|
|
@ -271,7 +271,7 @@
|
|||
id=unit-status
|
||||
font_size={DEFAULT_FONT_SMALL}
|
||||
ref=label-hp
|
||||
rect="+10,=-2,1022,+16"
|
||||
rect="+5,=-4,1022,+16"
|
||||
xanchor=right
|
||||
yanchor=fixed
|
||||
[/unit_status]
|
||||
|
@ -445,7 +445,7 @@
|
|||
id=unit-hp
|
||||
font_size={DEFAULT_FONT_SMALL}
|
||||
ref=label-hp
|
||||
rect="=,+0,+94,+14"
|
||||
rect="=,+0,1022,+14"
|
||||
prefix_literal=" "
|
||||
xanchor=right
|
||||
yanchor=fixed
|
||||
|
|
|
@ -63,7 +63,10 @@ def run_tool(tool,queue,command):
|
|||
if sys.platform=="win32":
|
||||
# Windows wants a string, Linux wants a list and Polly wants a cracker
|
||||
# Windows wants also strings flavoured with double quotes
|
||||
wrapped_line=map(wrap_elem,command)
|
||||
# since maps return iterators, we must cast them as lists, otherwise join won't work
|
||||
# not doing this causes an OSError: [WinError 87]
|
||||
# this doesn't happen on Python 2.7, because here map() returns a list
|
||||
wrapped_line=list(map(wrap_elem,command))
|
||||
queue.put_nowait(' '.join(wrapped_line)+"\n")
|
||||
si=subprocess.STARTUPINFO()
|
||||
si.dwFlags=subprocess.STARTF_USESHOWWINDOW|subprocess.SW_HIDE # to avoid showing a DOS prompt
|
||||
|
@ -173,8 +176,18 @@ If the widget isn't active, some options do not appear"""
|
|||
image=ICONS['select_all'],
|
||||
compound=LEFT,
|
||||
accelerator='Ctrl+A',
|
||||
command=lambda: self.widget.event_generate("<<SelectAll>>"))
|
||||
command=self.on_select_all)
|
||||
self.tk_popup(x,y) # self.post does not destroy the menu when clicking out of it
|
||||
def on_select_all(self):
|
||||
# disabled Text widgets have a different way to handle selection
|
||||
if isinstance(self.widget,Text):
|
||||
# adding a SEL tag to a chunk of text causes it to be selected
|
||||
self.widget.tag_add(SEL,"1.0",END)
|
||||
elif isinstance(self.widget,Entry) or \
|
||||
isinstance(self.widget,Spinbox) or \
|
||||
isinstance(self.widget,Combobox):
|
||||
# if the widget is active or readonly, just fire the correct event
|
||||
self.widget.event_generate("<<SelectAll>>")
|
||||
|
||||
class EntryContext(Entry):
|
||||
def __init__(self,parent,**kwargs):
|
||||
|
@ -188,12 +201,26 @@ Use like any other Entry widget"""
|
|||
# some mice don't even have two buttons, so the user is forced
|
||||
# to use Control + the only button
|
||||
# bear in mind that I don't have a Mac, so this point may be bugged
|
||||
if sys.platform=="darwin":
|
||||
self.bind("<Button-2>",self.on_right_click)
|
||||
self.bind("<Control-Button-1>",self.on_right_click)
|
||||
else:
|
||||
self.bind("<Button-3>",self.on_right_click)
|
||||
def on_right_click(self,event):
|
||||
# bind also the context menu key, for those keyboards that have it
|
||||
# that is, most of the Windows and Linux ones (however, in Win it's
|
||||
# called App, while on Linux is called Menu)
|
||||
# Mac doesn't have a context menu key on its keyboards, so no binding
|
||||
# finally, bind also the Shift+F10 shortcut (same as Menu/App key)
|
||||
# the call to tk windowingsystem is justified by the fact
|
||||
# that it is possible to install X11 over Darwin
|
||||
windowingsystem = self.tk.call('tk', 'windowingsystem')
|
||||
if windowingsystem == "win32": # Windows, both 32 and 64 bit
|
||||
self.bind("<Button-3>",self.on_context_menu)
|
||||
self.bind("<KeyPress-App>",self.on_context_menu)
|
||||
self.bind("<Shift-KeyPress-F10>",self.on_context_menu)
|
||||
elif windowingsystem == "aqua": # MacOS with Aqua
|
||||
self.bind("<Button-2>",self.on_context_menu)
|
||||
self.bind("<Control-Button-1>",self.on_context_menu)
|
||||
elif windowingsystem == "x11": # Linux, FreeBSD, Darwin with X11
|
||||
self.bind("<Button-3>",self.on_context_menu)
|
||||
self.bind("<KeyPress-Menu>",self.on_context_menu)
|
||||
self.bind("<Shift-KeyPress-F10>",self.on_context_menu)
|
||||
def on_context_menu(self,event):
|
||||
if str(self.cget('state')) != DISABLED:
|
||||
ContextMenu(event.x_root,event.y_root,event.widget)
|
||||
|
||||
|
@ -205,19 +232,49 @@ Use like any other Spinbox widget"""
|
|||
super().__init__(parent,**kwargs)
|
||||
else:
|
||||
Spinbox.__init__(self,parent,**kwargs)
|
||||
# on Mac the right button fires a Button-2 event, or so I'm told
|
||||
# some mice don't even have two buttons, so the user is forced
|
||||
# to use Control + the only button
|
||||
# bear in mind that I don't have a Mac, so this point may be bugged
|
||||
if sys.platform=="darwin":
|
||||
self.bind("<Button-2>",self.on_right_click)
|
||||
self.bind("<Control-Button-1>",self.on_right_click)
|
||||
else:
|
||||
self.bind("<Button-3>",self.on_right_click)
|
||||
def on_right_click(self,event):
|
||||
# see the above widget for an explanation of this block
|
||||
windowingsystem = self.tk.call('tk', 'windowingsystem')
|
||||
if windowingsystem == "win32":
|
||||
self.bind("<Button-3>",self.on_context_menu)
|
||||
self.bind("<KeyPress-App>",self.on_context_menu)
|
||||
self.bind("<Shift-KeyPress-F10>",self.on_context_menu)
|
||||
elif windowingsystem == "aqua":
|
||||
self.bind("<Button-2>",self.on_context_menu)
|
||||
self.bind("<Control-Button-1>",self.on_context_menu)
|
||||
elif windowingsystem == "x11":
|
||||
self.bind("<Button-3>",self.on_context_menu)
|
||||
self.bind("<KeyPress-Menu>",self.on_context_menu)
|
||||
self.bind("<Shift-KeyPress-F10>",self.on_context_menu)
|
||||
def on_context_menu(self,event):
|
||||
if str(self.cget('state')) != DISABLED:
|
||||
ContextMenu(event.x_root,event.y_root,event.widget)
|
||||
|
||||
class EnhancedText(Text):
|
||||
def __init__(self,*args,**kwargs):
|
||||
"""A subclass of Text with a context menu
|
||||
Use it like any other Text widget"""
|
||||
if sys.version_info.major>=3:
|
||||
super().__init__(*args,**kwargs)
|
||||
else:
|
||||
Text.__init__(self,*args,**kwargs)
|
||||
# see descriptions of above widgets
|
||||
windowingsystem = self.tk.call('tk', 'windowingsystem')
|
||||
if windowingsystem == "win32": # Windows, both 32 and 64 bit
|
||||
self.bind("<Button-3>",self.on_context_menu)
|
||||
self.bind("<KeyPress-App>",self.on_context_menu)
|
||||
self.bind("<Shift-KeyPress-F10>",self.on_context_menu)
|
||||
elif windowingsystem == "aqua": # MacOS with Aqua
|
||||
self.bind("<Button-2>",self.on_context_menu)
|
||||
self.bind("<Control-Button-1>",self.on_context_menu)
|
||||
elif windowingsystem == "x11": # Linux, FreeBSD, Darwin with X11
|
||||
self.bind("<Button-3>",self.on_context_menu)
|
||||
self.bind("<KeyPress-Menu>",self.on_context_menu)
|
||||
self.bind("<Shift-KeyPress-F10>",self.on_context_menu)
|
||||
def on_context_menu(self,event):
|
||||
# the disabled state in a Text widget is pretty much
|
||||
# like the readonly state in Entry, hence no state check
|
||||
ContextMenu(event.x_root,event.y_root,event.widget)
|
||||
|
||||
class SelectDirectory(LabelFrame):
|
||||
def __init__(self,parent,textvariable=None,**kwargs):
|
||||
"""A subclass of LabelFrame sporting a readonly Entry and a Button with a folder icon.
|
||||
|
@ -338,7 +395,7 @@ class WmllintTab(Frame):
|
|||
self.verbosity_frame.grid(row=0,
|
||||
column=1,
|
||||
sticky=N+E+S+W)
|
||||
self.verbosity_variable=IntVar(0)
|
||||
self.verbosity_variable=IntVar()
|
||||
self.radio_v0=Radiobutton(self.verbosity_frame,
|
||||
text="Terse",
|
||||
variable=self.verbosity_variable,
|
||||
|
@ -376,7 +433,7 @@ class WmllintTab(Frame):
|
|||
self.options_frame.grid(row=0,
|
||||
column=2,
|
||||
sticky=N+E+S+W)
|
||||
self.stripcr_variable=IntVar(0)
|
||||
self.stripcr_variable=BooleanVar()
|
||||
self.stripcr_check=Checkbutton(self.options_frame,
|
||||
text="Convert EOL characters to Unix style",
|
||||
variable=self.stripcr_variable)
|
||||
|
@ -384,7 +441,7 @@ class WmllintTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.missing_variable=IntVar(0)
|
||||
self.missing_variable=BooleanVar()
|
||||
self.missing_check=Checkbutton(self.options_frame,
|
||||
text="Don't warn about tags without side= keys",
|
||||
variable=self.missing_variable)
|
||||
|
@ -392,7 +449,7 @@ class WmllintTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.known_variable=IntVar(0)
|
||||
self.known_variable=BooleanVar()
|
||||
self.known_check=Checkbutton(self.options_frame,
|
||||
text="Disable checks for unknown units",
|
||||
variable=self.known_variable)
|
||||
|
@ -400,7 +457,7 @@ class WmllintTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.spell_variable=IntVar(0)
|
||||
self.spell_variable=BooleanVar()
|
||||
self.spell_check=Checkbutton(self.options_frame,
|
||||
text="Disable spellchecking",
|
||||
variable=self.spell_variable)
|
||||
|
@ -408,7 +465,7 @@ class WmllintTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.freeze_variable=IntVar(0)
|
||||
self.freeze_variable=BooleanVar()
|
||||
self.freeze_check=Checkbutton(self.options_frame,
|
||||
text="Ignore newlines in messages",
|
||||
variable=self.freeze_variable)
|
||||
|
@ -435,7 +492,7 @@ class WmlscopeTab(Frame):
|
|||
self.normal_options.grid(row=0,
|
||||
column=0,
|
||||
sticky=N+E+S+W)
|
||||
self.crossreference_variable=IntVar(0) # equivalent to warnlevel 1
|
||||
self.crossreference_variable=BooleanVar() # equivalent to warnlevel 1
|
||||
self.crossreference_check=Checkbutton(self.normal_options,
|
||||
text="Check for duplicate macro definitions",
|
||||
variable=self.crossreference_variable)
|
||||
|
@ -443,7 +500,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.collisions_variable=IntVar(0)
|
||||
self.collisions_variable=BooleanVar()
|
||||
self.collisions_check=Checkbutton(self.normal_options,
|
||||
text="Check for duplicate resource files",
|
||||
variable=self.collisions_variable)
|
||||
|
@ -451,7 +508,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.definitions_variable=IntVar(0)
|
||||
self.definitions_variable=BooleanVar()
|
||||
self.definitions_check=Checkbutton(self.normal_options,
|
||||
text="Make definition list",
|
||||
variable=self.definitions_variable)
|
||||
|
@ -459,7 +516,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.listfiles_variable=IntVar(0)
|
||||
self.listfiles_variable=BooleanVar()
|
||||
self.listfiles_check=Checkbutton(self.normal_options,
|
||||
text="List files that will be processed",
|
||||
variable=self.listfiles_variable)
|
||||
|
@ -467,7 +524,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.unresolved_variable=IntVar(0)
|
||||
self.unresolved_variable=BooleanVar()
|
||||
self.unresolved_check=Checkbutton(self.normal_options,
|
||||
text="Report unresolved macro references",
|
||||
variable=self.unresolved_variable)
|
||||
|
@ -475,7 +532,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.extracthelp_variable=IntVar(0)
|
||||
self.extracthelp_variable=BooleanVar()
|
||||
self.extracthelp_check=Checkbutton(self.normal_options,
|
||||
text="Extract help from macro definition comments",
|
||||
variable=self.extracthelp_variable)
|
||||
|
@ -483,7 +540,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.unchecked_variable=IntVar(0)
|
||||
self.unchecked_variable=BooleanVar()
|
||||
self.unchecked_check=Checkbutton(self.normal_options,
|
||||
text="Report all macros with untyped formals",
|
||||
variable=self.unchecked_variable)
|
||||
|
@ -491,7 +548,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.progress_variable=IntVar(0)
|
||||
self.progress_variable=BooleanVar()
|
||||
self.progress_check=Checkbutton(self.normal_options,
|
||||
text="Show progress",
|
||||
variable=self.progress_variable)
|
||||
|
@ -508,7 +565,7 @@ class WmlscopeTab(Frame):
|
|||
self.options_with_regexp.grid(row=0,
|
||||
column=2,
|
||||
sticky=N+E+S+W)
|
||||
self.exclude_variable=IntVar(0)
|
||||
self.exclude_variable=BooleanVar()
|
||||
self.exclude_check=Checkbutton(self.options_with_regexp,
|
||||
text="Exclude files matching regexp:",
|
||||
variable=self.exclude_variable,
|
||||
|
@ -525,7 +582,7 @@ class WmlscopeTab(Frame):
|
|||
column=1,
|
||||
sticky=E+W,
|
||||
padx=10)
|
||||
self.from_variable=IntVar(0)
|
||||
self.from_variable=BooleanVar()
|
||||
self.from_check=Checkbutton(self.options_with_regexp,
|
||||
text="Exclude files not matching regexp:",
|
||||
variable=self.from_variable,
|
||||
|
@ -542,7 +599,7 @@ class WmlscopeTab(Frame):
|
|||
column=1,
|
||||
sticky=E+W,
|
||||
padx=10)
|
||||
self.refcount_variable=IntVar(0)
|
||||
self.refcount_variable=BooleanVar()
|
||||
self.refcount_check=Checkbutton(self.options_with_regexp,
|
||||
text="Report only on macros referenced\nin at least n files:",
|
||||
variable=self.refcount_variable,
|
||||
|
@ -551,7 +608,7 @@ class WmlscopeTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.refcount_number=IntVar(0)
|
||||
self.refcount_number=IntVar()
|
||||
self.refcount_spin=SpinboxContext(self.options_with_regexp,
|
||||
from_=0,to=999,
|
||||
textvariable=self.refcount_number,
|
||||
|
@ -561,7 +618,7 @@ class WmlscopeTab(Frame):
|
|||
column=1,
|
||||
sticky=E+W,
|
||||
padx=10)
|
||||
self.typelist_variable=IntVar(0)
|
||||
self.typelist_variable=BooleanVar()
|
||||
self.typelist_check=Checkbutton(self.options_with_regexp,
|
||||
text="List actual & formal argtypes\nfor calls in fname",
|
||||
variable=self.typelist_variable,
|
||||
|
@ -578,7 +635,7 @@ class WmlscopeTab(Frame):
|
|||
column=1,
|
||||
sticky=E+W,
|
||||
padx=10)
|
||||
self.force_variable=IntVar(0)
|
||||
self.force_variable=BooleanVar()
|
||||
self.force_check=Checkbutton(self.options_with_regexp,
|
||||
text="Ignore refcount 0 on names\nmatching regexp:",
|
||||
variable=self.force_variable,
|
||||
|
@ -663,7 +720,7 @@ class WmlindentTab(Frame):
|
|||
self.options_frame.grid(row=0,
|
||||
column=1,
|
||||
sticky=N+E+S+W)
|
||||
self.verbose_variable=IntVar(0)
|
||||
self.verbose_variable=BooleanVar()
|
||||
self.verbose_check=Checkbutton(self.options_frame,
|
||||
text="Report also unchanged files",
|
||||
variable=self.verbose_variable)
|
||||
|
@ -671,7 +728,7 @@ class WmlindentTab(Frame):
|
|||
column=0,
|
||||
sticky=W,
|
||||
padx=10)
|
||||
self.exclude_variable=IntVar(0)
|
||||
self.exclude_variable=BooleanVar()
|
||||
self.exclude_check=Checkbutton(self.options_frame,
|
||||
text="Exclude files matching regexp:",
|
||||
variable=self.exclude_variable,
|
||||
|
@ -689,7 +746,7 @@ class WmlindentTab(Frame):
|
|||
column=1,
|
||||
sticky=E+W,
|
||||
padx=10)
|
||||
self.quiet_variable=IntVar(0)
|
||||
self.quiet_variable=BooleanVar()
|
||||
self.quiet_check=Checkbutton(self.options_frame,
|
||||
text="Do not generate output",
|
||||
variable=self.quiet_variable)
|
||||
|
@ -791,10 +848,10 @@ class MainFrame(Frame):
|
|||
self.output_frame.grid(row=3,
|
||||
column=0,
|
||||
sticky=N+E+S+W)
|
||||
self.text=Text(self.output_frame,
|
||||
wrap=WORD,
|
||||
state=DISABLED,
|
||||
takefocus=True)
|
||||
self.text=EnhancedText(self.output_frame,
|
||||
wrap=WORD,
|
||||
state=DISABLED,
|
||||
takefocus=True)
|
||||
self.text.grid(row=0,
|
||||
column=0,
|
||||
sticky=N+E+S+W)
|
||||
|
@ -1015,7 +1072,7 @@ Error code: {1}
|
|||
|
||||
Part of The Battle for Wesnoth project and released under the GNU GPL v2 license
|
||||
|
||||
Icons are taken from the Tango project, and are released in the Public Domain""")
|
||||
Icons are taken from the Tango Desktop Project (http://tango.freedesktop.org), and are released in the Public Domain""")
|
||||
|
||||
root=Tk()
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,15 +3,37 @@ changes may be omitted). For a complete list of changes, see the main
|
|||
changelog: https://github.com/wesnoth/wesnoth/blob/1.12/changelog
|
||||
|
||||
Version 1.11.18+dev:
|
||||
* Campaigns:
|
||||
* Legend of Wesmere:
|
||||
* Ka’lian under attack: fixed more issues due to new map size.
|
||||
* Ka’lian under attack: fixed two issues with fog. This fixes bug #22880.
|
||||
* Elves Last Stand: fixed not all elvish leaders being able to recruit.
|
||||
* Elves Last Stand: fixed bugs in Olurf and Olurf's party arrival.
|
||||
* Bounty Hunters: fixed several coordinate issues due to new map size.
|
||||
* Cliffs of Thoria: fixed so that yetis can be seen moving in hole in fog.
|
||||
* Fixed player team name in several scenarios.
|
||||
* Fixed player side carryover in several scenarios.
|
||||
* Language and i18n:
|
||||
* Updated translations: Galician, German, Italian, Portuguese,
|
||||
Scottish Gaelic, Slovak, Spanish.
|
||||
|
||||
|
||||
|
||||
Version 1.11.18:
|
||||
* Campaigns:
|
||||
* Eastern Invasion:
|
||||
* Updated maps for scenario 14, 16 and 17b.
|
||||
* Legend of Wesmere:
|
||||
* Fixed broken sides configuration and starting locations in several
|
||||
scenarios.
|
||||
* The Uprooting: fixed Arkildur not appearing in multiplayer mode.
|
||||
* Ka’lian under attack: fixed units and labels offset due to different map
|
||||
sizes after Kalenz and Landar appear (bug #22073).
|
||||
* Bounty Hunters: fixed Olurf being unable to recruit.
|
||||
* Human Alliance: completely redone and rebalanced. This fixes bug #21941,
|
||||
implements FR #16600, and addresses comments made in the feedback topic
|
||||
on the forums.
|
||||
* Chapter 4 is now available in multiplayer mode again
|
||||
* Minor (mostly cosmetic) changes to several maps
|
||||
* Under the Burning Suns:
|
||||
* Fixed recruited Desert Archers being always male.
|
||||
* Fixed malformed rand range errors during AI turns on medium difficulty
|
||||
|
@ -87,11 +109,11 @@ Version 1.11.16:
|
|||
* Fix bug that caused wrong or missing minimap data to be displayed in the
|
||||
preview pane when loading games.
|
||||
|
||||
|
||||
|
||||
Version 1.11.15:
|
||||
* Language and i18n:
|
||||
* Updated translations: Portuguese
|
||||
|
||||
|
||||
* Miscellaneous and bug fixes:
|
||||
* Reallow selection of another unit on same side without deselect first
|
||||
|
||||
|
|
|
@ -863,6 +863,10 @@ bool is_path_sep(char c)
|
|||
}
|
||||
std::string normalize_path(const std::string &fpath)
|
||||
{
|
||||
if (fpath.empty()) {
|
||||
return fpath;
|
||||
}
|
||||
|
||||
return bfs::absolute(fpath).string();
|
||||
}
|
||||
|
||||
|
|
|
@ -731,7 +731,12 @@ static surface get_hexed(const locator& i_locator)
|
|||
static surface get_scaled_to_hex(const locator& i_locator)
|
||||
{
|
||||
surface img = get_image(i_locator, HEXED);
|
||||
return scale_surface(img, zoom, zoom);
|
||||
|
||||
if (zoom < tile_size) {
|
||||
return scale_surface(img, zoom, zoom);
|
||||
} else {
|
||||
return scale_surface_sharp(img, zoom, zoom);
|
||||
}
|
||||
}
|
||||
|
||||
static surface get_tod_colored(const locator& i_locator)
|
||||
|
@ -748,7 +753,11 @@ static surface get_scaled_to_zoom(const locator& i_locator)
|
|||
surface res(get_image(i_locator, UNSCALED));
|
||||
// For some reason haloes seems to have invalid images, protect against crashing
|
||||
if(!res.null()) {
|
||||
return scale_surface(res, ((res.get()->w * zoom) / tile_size), ((res.get()->h * zoom) / tile_size));
|
||||
if (zoom < tile_size) {
|
||||
return scale_surface(res, ((res.get()->w * zoom) / tile_size), ((res.get()->h * zoom) / tile_size));
|
||||
} else {
|
||||
return scale_surface_sharp(res, ((res.get()->w * zoom) / tile_size), ((res.get()->h * zoom) / tile_size));
|
||||
}
|
||||
} else {
|
||||
return surface(NULL);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,16 @@
|
|||
/* corresponding test */
|
||||
#define isvalid(o) ((o) != luaO_nilobject)
|
||||
|
||||
#define api_checkvalidindex(L, i) api_check(L, isvalid(i), "invalid index")
|
||||
/* test for pseudo index */
|
||||
#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX)
|
||||
|
||||
/* test for valid but not pseudo index */
|
||||
#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
|
||||
|
||||
#define api_checkvalidindex(L, o) api_check(L, isvalid(o), "invalid index")
|
||||
|
||||
#define api_checkstackindex(L, i, o) \
|
||||
api_check(L, isstackindex(i, o), "index not in the stack")
|
||||
|
||||
|
||||
static TValue *index2addr (lua_State *L, int idx) {
|
||||
|
@ -45,7 +54,7 @@ static TValue *index2addr (lua_State *L, int idx) {
|
|||
if (o >= L->top) return NONVALIDVALUE;
|
||||
else return o;
|
||||
}
|
||||
else if (idx > LUA_REGISTRYINDEX) {
|
||||
else if (!ispseudo(idx)) { /* negative index */
|
||||
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
|
||||
return L->top + idx;
|
||||
}
|
||||
|
@ -136,7 +145,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
|
|||
** convert an acceptable stack index into an absolute index
|
||||
*/
|
||||
LUA_API int lua_absindex (lua_State *L, int idx) {
|
||||
return (idx > 0 || idx <= LUA_REGISTRYINDEX)
|
||||
return (idx > 0 || ispseudo(idx))
|
||||
? idx
|
||||
: cast_int(L->top - L->ci->func + idx);
|
||||
}
|
||||
|
@ -168,7 +177,7 @@ LUA_API void lua_remove (lua_State *L, int idx) {
|
|||
StkId p;
|
||||
lua_lock(L);
|
||||
p = index2addr(L, idx);
|
||||
api_checkvalidindex(L, p);
|
||||
api_checkstackindex(L, idx, p);
|
||||
while (++p < L->top) setobjs2s(L, p-1, p);
|
||||
L->top--;
|
||||
lua_unlock(L);
|
||||
|
@ -180,8 +189,9 @@ LUA_API void lua_insert (lua_State *L, int idx) {
|
|||
StkId q;
|
||||
lua_lock(L);
|
||||
p = index2addr(L, idx);
|
||||
api_checkvalidindex(L, p);
|
||||
for (q = L->top; q>p; q--) setobjs2s(L, q, q-1);
|
||||
api_checkstackindex(L, idx, p);
|
||||
for (q = L->top; q > p; q--) /* use L->top as a temporary */
|
||||
setobjs2s(L, q, q - 1);
|
||||
setobjs2s(L, p, L->top);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
@ -211,7 +221,6 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
|
|||
TValue *fr;
|
||||
lua_lock(L);
|
||||
fr = index2addr(L, fromidx);
|
||||
api_checkvalidindex(L, fr);
|
||||
moveto(L, fr, toidx);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
@ -275,7 +284,7 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) {
|
|||
}
|
||||
|
||||
|
||||
LUA_API void lua_arith (lua_State *L, int op) {
|
||||
LUA_API void lua_arith (lua_State *L, int op) {
|
||||
StkId o1; /* 1st operand */
|
||||
StkId o2; /* 2nd operand */
|
||||
lua_lock(L);
|
||||
|
@ -289,7 +298,7 @@ LUA_API void lua_arith (lua_State *L, int op) {
|
|||
o1 = L->top - 2;
|
||||
o2 = L->top - 1;
|
||||
if (ttisnumber(o1) && ttisnumber(o2)) {
|
||||
changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
|
||||
setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2)));
|
||||
}
|
||||
else
|
||||
luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD));
|
||||
|
@ -605,7 +614,6 @@ LUA_API void lua_gettable (lua_State *L, int idx) {
|
|||
StkId t;
|
||||
lua_lock(L);
|
||||
t = index2addr(L, idx);
|
||||
api_checkvalidindex(L, t);
|
||||
luaV_gettable(L, t, L->top - 1, L->top - 1);
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
@ -615,7 +623,6 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) {
|
|||
StkId t;
|
||||
lua_lock(L);
|
||||
t = index2addr(L, idx);
|
||||
api_checkvalidindex(L, t);
|
||||
setsvalue2s(L, L->top, luaS_new(L, k));
|
||||
api_incr_top(L);
|
||||
luaV_gettable(L, t, L->top - 1, L->top - 1);
|
||||
|
@ -703,7 +710,6 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) {
|
|||
StkId o;
|
||||
lua_lock(L);
|
||||
o = index2addr(L, idx);
|
||||
api_checkvalidindex(L, o);
|
||||
api_check(L, ttisuserdata(o), "userdata expected");
|
||||
if (uvalue(o)->env) {
|
||||
sethvalue(L, L->top, uvalue(o)->env);
|
||||
|
@ -737,7 +743,6 @@ LUA_API void lua_settable (lua_State *L, int idx) {
|
|||
lua_lock(L);
|
||||
api_checknelems(L, 2);
|
||||
t = index2addr(L, idx);
|
||||
api_checkvalidindex(L, t);
|
||||
luaV_settable(L, t, L->top - 2, L->top - 1);
|
||||
L->top -= 2; /* pop index and value */
|
||||
lua_unlock(L);
|
||||
|
@ -749,7 +754,6 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
|
|||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
t = index2addr(L, idx);
|
||||
api_checkvalidindex(L, t);
|
||||
setsvalue2s(L, L->top++, luaS_new(L, k));
|
||||
luaV_settable(L, t, L->top - 1, L->top - 2);
|
||||
L->top -= 2; /* pop value and key */
|
||||
|
@ -805,7 +809,6 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
|||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
obj = index2addr(L, objindex);
|
||||
api_checkvalidindex(L, obj);
|
||||
if (ttisnil(L->top - 1))
|
||||
mt = NULL;
|
||||
else {
|
||||
|
@ -815,9 +818,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
|||
switch (ttypenv(obj)) {
|
||||
case LUA_TTABLE: {
|
||||
hvalue(obj)->metatable = mt;
|
||||
if (mt)
|
||||
if (mt) {
|
||||
luaC_objbarrierback(L, gcvalue(obj), mt);
|
||||
luaC_checkfinalizer(L, gcvalue(obj), mt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LUA_TUSERDATA: {
|
||||
|
@ -844,7 +848,6 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
|
|||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
o = index2addr(L, idx);
|
||||
api_checkvalidindex(L, o);
|
||||
api_check(L, ttisuserdata(o), "userdata expected");
|
||||
if (ttisnil(L->top - 1))
|
||||
uvalue(o)->env = NULL;
|
||||
|
@ -931,7 +934,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
|
|||
func = 0;
|
||||
else {
|
||||
StkId o = index2addr(L, errfunc);
|
||||
api_checkvalidindex(L, o);
|
||||
api_checkstackindex(L, errfunc, o);
|
||||
func = savestack(L, o);
|
||||
}
|
||||
c.func = L->top - (nargs+1); /* function to be called */
|
||||
|
@ -944,7 +947,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
|
|||
ci->u.c.k = k; /* save continuation */
|
||||
ci->u.c.ctx = ctx; /* save context */
|
||||
/* save information for error recovery */
|
||||
ci->u.c.extra = savestack(L, c.func);
|
||||
ci->extra = savestack(L, c.func);
|
||||
ci->u.c.old_allowhook = L->allowhook;
|
||||
ci->u.c.old_errfunc = L->errfunc;
|
||||
L->errfunc = func;
|
||||
|
@ -1000,7 +1003,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) {
|
|||
}
|
||||
|
||||
|
||||
LUA_API int lua_status (lua_State *L) {
|
||||
LUA_API int lua_status (lua_State *L) {
|
||||
return L->status;
|
||||
}
|
||||
|
||||
|
@ -1039,17 +1042,17 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
|
|||
}
|
||||
case LUA_GCSTEP: {
|
||||
if (g->gckind == KGC_GEN) { /* generational mode? */
|
||||
res = (g->lastmajormem == 0); /* 1 if will do major collection */
|
||||
res = (g->GCestimate == 0); /* true if it will do major collection */
|
||||
luaC_forcestep(L); /* do a single step */
|
||||
}
|
||||
else {
|
||||
while (data-- >= 0) {
|
||||
luaC_forcestep(L);
|
||||
if (g->gcstate == GCSpause) { /* end of cycle? */
|
||||
res = 1; /* signal it */
|
||||
break;
|
||||
}
|
||||
}
|
||||
lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE;
|
||||
if (g->gcrunning)
|
||||
debt += g->GCdebt; /* include current debt */
|
||||
luaE_setdebt(g, debt);
|
||||
luaC_forcestep(L);
|
||||
if (g->gcstate == GCSpause) /* end of cycle? */
|
||||
res = 1; /* signal it */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1097,7 +1100,7 @@ LUA_API int lua_error (lua_State *L) {
|
|||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
luaG_errormsg(L);
|
||||
lua_unlock(L);
|
||||
/* code unreachable; will unlock when control actually leaves the kernel */
|
||||
return 0; /* to avoid warnings */
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
|||
if (*ar->namewhat != '\0') /* is there a name? */
|
||||
lua_pushfstring(L, "function " LUA_QS, ar->name);
|
||||
else if (*ar->what == 'm') /* main? */
|
||||
lua_pushfstring(L, "main chunk");
|
||||
lua_pushliteral(L, "main chunk");
|
||||
else if (*ar->what == 'C') {
|
||||
if (pushglobalfuncname(L, ar)) {
|
||||
lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
|
||||
|
@ -157,7 +157,8 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
|
|||
if (strcmp(ar.namewhat, "method") == 0) {
|
||||
narg--; /* do not count `self' */
|
||||
if (narg == 0) /* error is in the self argument itself? */
|
||||
return luaL_error(L, "calling " LUA_QS " on bad self", ar.name);
|
||||
return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
|
||||
ar.name, extramsg);
|
||||
}
|
||||
if (ar.name == NULL)
|
||||
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
||||
|
@ -216,7 +217,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
|||
if (fname)
|
||||
lua_pushfstring(L, "%s: %s", fname, strerror(en));
|
||||
else
|
||||
lua_pushfstring(L, "%s", strerror(en));
|
||||
lua_pushstring(L, strerror(en));
|
||||
lua_pushinteger(L, en);
|
||||
return 3;
|
||||
}
|
||||
|
@ -440,7 +441,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
|
|||
if (B->size - B->n < sz) { /* not enough space? */
|
||||
char *newbuff;
|
||||
size_t newsize = B->size * 2; /* double buffer size */
|
||||
if (newsize - B->n < sz) /* not bit enough? */
|
||||
if (newsize - B->n < sz) /* not big enough? */
|
||||
newsize = B->n + sz;
|
||||
if (newsize < B->n || newsize - B->n < sz)
|
||||
luaL_error(L, "buffer too large");
|
||||
|
@ -522,11 +523,11 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
|
|||
|
||||
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||
int ref;
|
||||
t = lua_absindex(L, t);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* remove from stack */
|
||||
return LUA_REFNIL; /* `nil' has a unique fixed reference */
|
||||
}
|
||||
t = lua_absindex(L, t);
|
||||
lua_rawgeti(L, t, freelist); /* get first free element */
|
||||
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
|
||||
lua_pop(L, 1); /* remove it from stack */
|
||||
|
@ -600,7 +601,7 @@ static int skipBOM (LoadF *lf) {
|
|||
lf->n = 0;
|
||||
do {
|
||||
c = getc(lf->f);
|
||||
if (c == EOF || c != *(unsigned char *)p++) return c;
|
||||
if (c == EOF || c != *(const unsigned char *)p++) return c;
|
||||
lf->buff[lf->n++] = c; /* to be read by the parser */
|
||||
} while (*p != '\0');
|
||||
lf->n = 0; /* prefix matched; discard it */
|
||||
|
@ -618,8 +619,10 @@ static int skipBOM (LoadF *lf) {
|
|||
static int skipcomment (LoadF *lf, int *cp) {
|
||||
int c = *cp = skipBOM(lf);
|
||||
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
||||
while ((c = getc(lf->f)) != EOF && c != '\n') ; /* skip first line */
|
||||
*cp = getc(lf->f); /* skip end-of-line */
|
||||
do { /* skip first line */
|
||||
c = getc(lf->f);
|
||||
} while (c != EOF && c != '\n') ;
|
||||
*cp = getc(lf->f); /* skip end-of-line, if present */
|
||||
return 1; /* there was a comment */
|
||||
}
|
||||
else return 0; /* no comment */
|
||||
|
@ -845,6 +848,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
|
|||
** Returns with only the table at the stack.
|
||||
*/
|
||||
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
||||
luaL_checkversion(L);
|
||||
luaL_checkstack(L, nup, "too many upvalues");
|
||||
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
||||
int i;
|
||||
|
@ -865,8 +869,8 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
|
|||
lua_getfield(L, idx, fname);
|
||||
if (lua_istable(L, -1)) return 1; /* table already there */
|
||||
else {
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_pop(L, 1); /* remove previous result */
|
||||
idx = lua_absindex(L, idx);
|
||||
lua_newtable(L);
|
||||
lua_pushvalue(L, -1); /* copy to be left at top */
|
||||
lua_setfield(L, idx, fname); /* assign new table to field */
|
||||
|
@ -891,10 +895,8 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
|
|||
lua_setfield(L, -2, modname); /* _LOADED[modname] = module */
|
||||
lua_pop(L, 1); /* remove _LOADED table */
|
||||
if (glb) {
|
||||
lua_pushglobaltable(L);
|
||||
lua_pushvalue(L, -2); /* copy of 'mod' */
|
||||
lua_setfield(L, -2, modname); /* _G[modname] = module */
|
||||
lua_pop(L, 1); /* remove _G table */
|
||||
lua_pushvalue(L, -1); /* copy of 'mod' */
|
||||
lua_setglobal(L, modname); /* _G[modname] = module */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -241,10 +241,16 @@ static int luaB_ipairs (lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
static int load_aux (lua_State *L, int status) {
|
||||
if (status == LUA_OK)
|
||||
static int load_aux (lua_State *L, int status, int envidx) {
|
||||
if (status == LUA_OK) {
|
||||
if (envidx != 0) { /* 'env' parameter? */
|
||||
lua_pushvalue(L, envidx); /* environment for loaded function */
|
||||
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
|
||||
lua_pop(L, 1); /* remove 'env' if not used by previous call */
|
||||
}
|
||||
return 1;
|
||||
else {
|
||||
}
|
||||
else { /* error (message is on top of the stack) */
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2); /* put before error message */
|
||||
return 2; /* return nil plus error message */
|
||||
|
@ -255,13 +261,9 @@ static int load_aux (lua_State *L, int status) {
|
|||
static int luaB_loadfile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
const char *mode = luaL_optstring(L, 2, NULL);
|
||||
int env = !lua_isnone(L, 3); /* 'env' parameter? */
|
||||
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
||||
int status = luaL_loadfilex(L, fname, mode);
|
||||
if (status == LUA_OK && env) { /* 'env' parameter? */
|
||||
lua_pushvalue(L, 3);
|
||||
lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */
|
||||
}
|
||||
return load_aux(L, status);
|
||||
return load_aux(L, status, env);
|
||||
}
|
||||
|
||||
|
||||
|
@ -292,6 +294,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
|||
lua_pushvalue(L, 1); /* get function */
|
||||
lua_call(L, 0, 1); /* call it */
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* pop result */
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -305,9 +308,9 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
|||
static int luaB_load (lua_State *L) {
|
||||
int status;
|
||||
size_t l;
|
||||
int top = lua_gettop(L);
|
||||
const char *s = lua_tolstring(L, 1, &l);
|
||||
const char *mode = luaL_optstring(L, 3, "bt");
|
||||
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
||||
if (s != NULL) { /* loading a string? */
|
||||
const char *chunkname = luaL_optstring(L, 2, s);
|
||||
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
||||
|
@ -318,11 +321,7 @@ static int luaB_load (lua_State *L) {
|
|||
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
|
||||
status = lua_load(L, generic_reader, NULL, chunkname, mode);
|
||||
}
|
||||
if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */
|
||||
lua_pushvalue(L, 4); /* environment for loaded function */
|
||||
lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */
|
||||
}
|
||||
return load_aux(L, status);
|
||||
return load_aux(L, status, env);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
@ -336,7 +335,8 @@ static int dofilecont (lua_State *L) {
|
|||
static int luaB_dofile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
lua_settop(L, 1);
|
||||
if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L);
|
||||
if (luaL_loadfile(L, fname) != LUA_OK)
|
||||
return lua_error(L);
|
||||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
||||
return dofilecont(L);
|
||||
}
|
||||
|
|
|
@ -128,7 +128,8 @@ static int b_rot (lua_State *L, int i) {
|
|||
b_uint r = luaL_checkunsigned(L, 1);
|
||||
i &= (LUA_NBITS - 1); /* i = i % NBITS */
|
||||
r = trim(r);
|
||||
r = (r << i) | (r >> (LUA_NBITS - i));
|
||||
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
|
||||
r = (r << i) | (r >> (LUA_NBITS - i));
|
||||
lua_pushunsigned(L, trim(r));
|
||||
return 1;
|
||||
}
|
||||
|
@ -146,7 +147,9 @@ static int b_rrot (lua_State *L) {
|
|||
|
||||
/*
|
||||
** get field and width arguments for field-manipulation functions,
|
||||
** checking whether they are valid
|
||||
** checking whether they are valid.
|
||||
** ('luaL_error' called without 'return' to avoid later warnings about
|
||||
** 'width' being used uninitialized.)
|
||||
*/
|
||||
static int fieldargs (lua_State *L, int farg, int *width) {
|
||||
int f = luaL_checkint(L, farg);
|
||||
|
|
|
@ -329,10 +329,9 @@ int luaK_numberK (FuncState *fs, lua_Number r) {
|
|||
setnvalue(&o, r);
|
||||
if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */
|
||||
/* use raw representation as key to avoid numeric problems */
|
||||
setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r)));
|
||||
incr_top(L);
|
||||
n = addk(fs, L->top - 1, &o);
|
||||
L->top--;
|
||||
setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r)));
|
||||
n = addk(fs, L->top - 1, &o);
|
||||
L->top--;
|
||||
}
|
||||
else
|
||||
n = addk(fs, &o, &o); /* regular case */
|
||||
|
@ -425,7 +424,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
|||
luaK_nil(fs, reg, 1);
|
||||
break;
|
||||
}
|
||||
case VFALSE: case VTRUE: {
|
||||
case VFALSE: case VTRUE: {
|
||||
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -72,15 +72,16 @@ static int luaB_auxwrap (lua_State *L) {
|
|||
lua_insert(L, -2);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
lua_error(L); /* propagate error */
|
||||
return lua_error(L); /* propagate error */
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cocreate (lua_State *L) {
|
||||
lua_State *NL = lua_newthread(L);
|
||||
lua_State *NL;
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
NL = lua_newthread(L);
|
||||
lua_pushvalue(L, 1); /* move function to top */
|
||||
lua_xmove(L, NL, 1); /* move function from L to NL */
|
||||
return 1;
|
||||
|
|
|
@ -252,14 +252,15 @@ static int db_upvaluejoin (lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY);
|
||||
#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
|
||||
|
||||
|
||||
static void hookf (lua_State *L, lua_Debug *ar) {
|
||||
static const char *const hooknames[] =
|
||||
{"call", "return", "line", "count", "tail call"};
|
||||
gethooktable(L);
|
||||
lua_rawgetp(L, -1, L);
|
||||
lua_pushthread(L);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isfunction(L, -1)) {
|
||||
lua_pushstring(L, hooknames[(int)ar->event]);
|
||||
if (ar->currentline >= 0)
|
||||
|
@ -305,10 +306,15 @@ static int db_sethook (lua_State *L) {
|
|||
count = luaL_optint(L, arg+3, 0);
|
||||
func = hookf; mask = makemask(smask, count);
|
||||
}
|
||||
gethooktable(L);
|
||||
if (gethooktable(L) == 0) { /* creating hook table? */
|
||||
lua_pushstring(L, "k");
|
||||
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
|
||||
}
|
||||
lua_pushthread(L1); lua_xmove(L1, L, 1);
|
||||
lua_pushvalue(L, arg+1);
|
||||
lua_rawsetp(L, -2, L1); /* set new hook */
|
||||
lua_pop(L, 1); /* remove hook table */
|
||||
lua_rawset(L, -3); /* set new hook */
|
||||
lua_sethook(L1, func, mask, count); /* set hooks */
|
||||
return 0;
|
||||
}
|
||||
|
@ -324,7 +330,8 @@ static int db_gethook (lua_State *L) {
|
|||
lua_pushliteral(L, "external hook");
|
||||
else {
|
||||
gethooktable(L);
|
||||
lua_rawgetp(L, -1, L1); /* get hook */
|
||||
lua_pushthread(L1); lua_xmove(L1, L, 1);
|
||||
lua_rawget(L, -2); /* get hook */
|
||||
lua_remove(L, -2); /* remove hook table */
|
||||
}
|
||||
lua_pushstring(L, unmakemask(mask, buff));
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
|
||||
|
||||
|
||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
|
||||
|
||||
|
||||
|
@ -172,7 +175,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||
|
||||
|
||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
if (cl == NULL || cl->c.isC) {
|
||||
if (noLuaClosure(cl)) {
|
||||
ar->source = "=[C]";
|
||||
ar->linedefined = -1;
|
||||
ar->lastlinedefined = -1;
|
||||
|
@ -190,9 +193,9 @@ static void funcinfo (lua_Debug *ar, Closure *cl) {
|
|||
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (f == NULL || f->c.isC) {
|
||||
if (noLuaClosure(f)) {
|
||||
setnilvalue(L->top);
|
||||
incr_top(L);
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
|
@ -200,7 +203,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
|||
int *lineinfo = f->l.p->lineinfo;
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue(L, L->top, t); /* push it on stack */
|
||||
incr_top(L);
|
||||
api_incr_top(L);
|
||||
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
|
||||
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
|
||||
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
|
||||
|
@ -209,7 +212,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
|||
|
||||
|
||||
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
Closure *f, CallInfo *ci) {
|
||||
Closure *f, CallInfo *ci) {
|
||||
int status = 1;
|
||||
for (; *what; what++) {
|
||||
switch (*what) {
|
||||
|
@ -223,7 +226,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
|||
}
|
||||
case 'u': {
|
||||
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
||||
if (f == NULL || f->c.isC) {
|
||||
if (noLuaClosure(f)) {
|
||||
ar->isvararg = 1;
|
||||
ar->nparams = 0;
|
||||
}
|
||||
|
@ -281,7 +284,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|||
status = auxgetinfo(L, what, ar, cl, ci);
|
||||
if (strchr(what, 'f')) {
|
||||
setobjs2s(L, L->top, func);
|
||||
incr_top(L);
|
||||
api_incr_top(L);
|
||||
}
|
||||
if (strchr(what, 'L'))
|
||||
collectvalidlines(L, cl);
|
||||
|
@ -323,12 +326,20 @@ static void kname (Proto *p, int pc, int c, const char **name) {
|
|||
}
|
||||
|
||||
|
||||
static int filterpc (int pc, int jmptarget) {
|
||||
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
||||
return -1; /* cannot know who sets that register */
|
||||
else return pc; /* current position sets that register */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** try to find last instruction before 'lastpc' that modified register 'reg'
|
||||
*/
|
||||
static int findsetreg (Proto *p, int lastpc, int reg) {
|
||||
int pc;
|
||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||
int jmptarget = 0; /* any code before this address is conditional */
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
|
@ -337,33 +348,38 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
|
|||
case OP_LOADNIL: {
|
||||
int b = GETARG_B(i);
|
||||
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
||||
setreg = pc;
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
case OP_TFORCALL: {
|
||||
if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
|
||||
if (reg >= a + 2) /* affect all regs above its base */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL: {
|
||||
if (reg >= a) setreg = pc; /* affect all registers above base */
|
||||
if (reg >= a) /* affect all registers above base */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
case OP_JMP: {
|
||||
int b = GETARG_sBx(i);
|
||||
int dest = pc + 1 + b;
|
||||
/* jump is forward and do not skip `lastpc'? */
|
||||
if (pc < dest && dest <= lastpc)
|
||||
pc += b; /* do the jump */
|
||||
if (pc < dest && dest <= lastpc) {
|
||||
if (dest > jmptarget)
|
||||
jmptarget = dest; /* update 'jmptarget' */
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_TEST: {
|
||||
if (reg == a) setreg = pc; /* jumped code can change 'a' */
|
||||
if (reg == a) /* jumped code can change 'a' */
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (testAMode(op) && reg == a) /* any instruction that set A */
|
||||
setreg = pc;
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -514,7 +530,7 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
|||
|
||||
l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
|
||||
if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
|
||||
lua_assert(!ttisstring(p1) && !ttisnumber(p2));
|
||||
lua_assert(!ttisstring(p1) && !ttisnumber(p1));
|
||||
luaG_typeerror(L, p1, "concatenate");
|
||||
}
|
||||
|
||||
|
@ -559,7 +575,7 @@ l_noret luaG_errormsg (lua_State *L) {
|
|||
if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
|
||||
setobjs2s(L, L->top, L->top - 1); /* move argument */
|
||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
||||
incr_top(L);
|
||||
L->top++;
|
||||
luaD_call(L, L->top - 2, 1, 0); /* call it */
|
||||
}
|
||||
luaD_throw(L, LUA_ERRRUN);
|
||||
|
|
|
@ -276,6 +276,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
|
|||
StkId base, fixed;
|
||||
lua_assert(actual >= nfixargs);
|
||||
/* move fixed parameters to final position */
|
||||
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
|
||||
fixed = L->top - actual; /* first fixed argument */
|
||||
base = L->top; /* final position of first argument */
|
||||
for (i=0; i<nfixargs; i++) {
|
||||
|
@ -327,6 +328,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
|||
ci->top = L->top + LUA_MINSTACK;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->callstatus = 0;
|
||||
luaC_checkGC(L); /* stack grow uses memory */
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
luaD_hook(L, LUA_HOOKCALL, -1);
|
||||
lua_unlock(L);
|
||||
|
@ -339,12 +341,18 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
|||
case LUA_TLCL: { /* Lua function: prepare its call */
|
||||
StkId base;
|
||||
Proto *p = clLvalue(func)->p;
|
||||
luaD_checkstack(L, p->maxstacksize);
|
||||
func = restorestack(L, funcr);
|
||||
n = cast_int(L->top - func) - 1; /* number of real arguments */
|
||||
luaD_checkstack(L, p->maxstacksize);
|
||||
for (; n < p->numparams; n++)
|
||||
setnilvalue(L->top++); /* complete missing arguments */
|
||||
base = (!p->is_vararg) ? func + 1 : adjust_varargs(L, p, n);
|
||||
if (!p->is_vararg) {
|
||||
func = restorestack(L, funcr);
|
||||
base = func + 1;
|
||||
}
|
||||
else {
|
||||
base = adjust_varargs(L, p, n);
|
||||
func = restorestack(L, funcr); /* previous call can change stack */
|
||||
}
|
||||
ci = next_ci(L); /* now 'enter' new function */
|
||||
ci->nresults = nresults;
|
||||
ci->func = func;
|
||||
|
@ -354,6 +362,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
|
|||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->callstatus = CIST_LUA;
|
||||
L->top = ci->top;
|
||||
luaC_checkGC(L); /* stack grow uses memory */
|
||||
if (L->hookmask & LUA_MASKCALL)
|
||||
callhook(L, ci);
|
||||
return 0;
|
||||
|
@ -409,7 +418,6 @@ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
|
|||
luaV_execute(L); /* call it */
|
||||
if (!allowyield) L->nny--;
|
||||
L->nCcalls--;
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
|
||||
|
||||
|
@ -418,9 +426,11 @@ static void finishCcall (lua_State *L) {
|
|||
int n;
|
||||
lua_assert(ci->u.c.k != NULL); /* must have a continuation */
|
||||
lua_assert(L->nny == 0);
|
||||
/* finish 'luaD_call' */
|
||||
L->nCcalls--;
|
||||
/* finish 'lua_callk' */
|
||||
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
|
||||
ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
|
||||
L->errfunc = ci->u.c.old_errfunc;
|
||||
}
|
||||
/* finish 'lua_callk'/'lua_pcall' */
|
||||
adjustresults(L, ci->nresults);
|
||||
/* call continuation function */
|
||||
if (!(ci->callstatus & CIST_STAT)) /* no call status? */
|
||||
|
@ -469,7 +479,7 @@ static int recover (lua_State *L, int status) {
|
|||
CallInfo *ci = findpcall(L);
|
||||
if (ci == NULL) return 0; /* no recovery point */
|
||||
/* "finish" luaD_pcall */
|
||||
oldtop = restorestack(L, ci->u.c.extra);
|
||||
oldtop = restorestack(L, ci->extra);
|
||||
luaF_close(L, oldtop);
|
||||
seterrorobj(L, status, oldtop);
|
||||
L->ci = ci;
|
||||
|
@ -491,7 +501,7 @@ static int recover (lua_State *L, int status) {
|
|||
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
|
||||
L->top = firstArg; /* remove args from the stack */
|
||||
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
|
||||
incr_top(L);
|
||||
api_incr_top(L);
|
||||
luaD_throw(L, -1); /* jump back to 'lua_resume' */
|
||||
}
|
||||
|
||||
|
@ -500,9 +510,10 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
|
|||
** do the work for 'lua_resume' in protected mode
|
||||
*/
|
||||
static void resume (lua_State *L, void *ud) {
|
||||
int nCcalls = L->nCcalls;
|
||||
StkId firstArg = cast(StkId, ud);
|
||||
CallInfo *ci = L->ci;
|
||||
if (L->nCcalls >= LUAI_MAXCCALLS)
|
||||
if (nCcalls >= LUAI_MAXCCALLS)
|
||||
resume_error(L, "C stack overflow", firstArg);
|
||||
if (L->status == LUA_OK) { /* may be starting a coroutine */
|
||||
if (ci != &L->base_ci) /* not in base level? */
|
||||
|
@ -515,10 +526,10 @@ static void resume (lua_State *L, void *ud) {
|
|||
resume_error(L, "cannot resume dead coroutine", firstArg);
|
||||
else { /* resuming from previous yield */
|
||||
L->status = LUA_OK;
|
||||
ci->func = restorestack(L, ci->extra);
|
||||
if (isLua(ci)) /* yielded inside a hook? */
|
||||
luaV_execute(L); /* just continue running Lua code */
|
||||
else { /* 'common' yield */
|
||||
ci->func = restorestack(L, ci->u.c.extra);
|
||||
if (ci->u.c.k != NULL) { /* does it have a continuation? */
|
||||
int n;
|
||||
ci->u.c.status = LUA_YIELD; /* 'default' status */
|
||||
|
@ -529,16 +540,17 @@ static void resume (lua_State *L, void *ud) {
|
|||
api_checknelems(L, n);
|
||||
firstArg = L->top - n; /* yield results come from continuation */
|
||||
}
|
||||
L->nCcalls--; /* finish 'luaD_call' */
|
||||
luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
|
||||
}
|
||||
unroll(L, NULL);
|
||||
}
|
||||
lua_assert(nCcalls == L->nCcalls);
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
|
||||
int status;
|
||||
int oldnny = L->nny; /* save 'nny' */
|
||||
lua_lock(L);
|
||||
luai_userstateresume(L, nargs);
|
||||
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
|
||||
|
@ -560,7 +572,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
|
|||
}
|
||||
lua_assert(status == L->status);
|
||||
}
|
||||
L->nny = 1; /* do not allow yields */
|
||||
L->nny = oldnny; /* restore 'nny' */
|
||||
L->nCcalls--;
|
||||
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
|
||||
lua_unlock(L);
|
||||
|
@ -575,18 +587,18 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
|
|||
api_checknelems(L, nresults);
|
||||
if (L->nny > 0) {
|
||||
if (L != G(L)->mainthread)
|
||||
luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
|
||||
luaG_runerror(L, "attempt to yield across a C-call boundary");
|
||||
else
|
||||
luaG_runerror(L, "attempt to yield from outside a coroutine");
|
||||
}
|
||||
L->status = LUA_YIELD;
|
||||
ci->extra = savestack(L, ci->func); /* save current 'func' */
|
||||
if (isLua(ci)) { /* inside a hook? */
|
||||
api_check(L, k == NULL, "hooks cannot continue after yielding");
|
||||
}
|
||||
else {
|
||||
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
|
||||
ci->u.c.ctx = ctx; /* save context */
|
||||
ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */
|
||||
ci->func = L->top - nresults - 1; /* protect stack below results */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
|
@ -643,24 +655,23 @@ static void checkmode (lua_State *L, const char *mode, const char *x) {
|
|||
|
||||
static void f_parser (lua_State *L, void *ud) {
|
||||
int i;
|
||||
Proto *tf;
|
||||
Closure *cl;
|
||||
struct SParser *p = cast(struct SParser *, ud);
|
||||
int c = zgetc(p->z); /* read first character */
|
||||
if (c == LUA_SIGNATURE[0]) {
|
||||
checkmode(L, p->mode, "binary");
|
||||
tf = luaU_undump(L, p->z, &p->buff, p->name);
|
||||
cl = luaU_undump(L, p->z, &p->buff, p->name);
|
||||
}
|
||||
else {
|
||||
checkmode(L, p->mode, "text");
|
||||
tf = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
|
||||
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
|
||||
}
|
||||
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
|
||||
for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */
|
||||
UpVal *up = luaF_newupval(L);
|
||||
cl->l.upvals[i] = up;
|
||||
luaC_objbarrier(L, cl, up);
|
||||
}
|
||||
setptvalue2s(L, L->top, tf);
|
||||
incr_top(L);
|
||||
cl = luaF_newLclosure(L, tf);
|
||||
setclLvalue(L, L->top - 1, cl);
|
||||
for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */
|
||||
cl->l.upvals[i] = luaF_newupval(L);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -83,8 +83,8 @@ static void DumpConstants(const Proto* f, DumpState* D)
|
|||
for (i=0; i<n; i++)
|
||||
{
|
||||
const TValue* o=&f->k[i];
|
||||
DumpChar(ttype(o),D);
|
||||
switch (ttype(o))
|
||||
DumpChar(ttypenv(o),D);
|
||||
switch (ttypenv(o))
|
||||
{
|
||||
case LUA_TNIL:
|
||||
break;
|
||||
|
@ -97,6 +97,7 @@ static void DumpConstants(const Proto* f, DumpState* D)
|
|||
case LUA_TSTRING:
|
||||
DumpString(rawtsvalue(o),D);
|
||||
break;
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
n=f->sizep;
|
||||
|
|
|
@ -20,18 +20,15 @@
|
|||
|
||||
|
||||
Closure *luaF_newCclosure (lua_State *L, int n) {
|
||||
Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl;
|
||||
c->c.isC = 1;
|
||||
Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
|
||||
c->c.nupvalues = cast_byte(n);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
Closure *luaF_newLclosure (lua_State *L, Proto *p) {
|
||||
int n = p->sizeupvalues;
|
||||
Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl;
|
||||
c->l.isC = 0;
|
||||
c->l.p = p;
|
||||
Closure *luaF_newLclosure (lua_State *L, int n) {
|
||||
Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
|
||||
c->l.p = NULL;
|
||||
c->l.nupvalues = cast_byte(n);
|
||||
while (n--) c->l.upvals[n] = NULL;
|
||||
return c;
|
||||
|
@ -54,12 +51,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
|
||||
GCObject *o = obj2gco(p);
|
||||
lua_assert(p->v != &p->u.value);
|
||||
lua_assert(!isold(o) || isold(obj2gco(L)));
|
||||
if (p->v == level) { /* found a corresponding upvalue? */
|
||||
if (isdead(g, o)) /* is it dead? */
|
||||
changewhite(o); /* resurrect it */
|
||||
return p;
|
||||
}
|
||||
resetoldbit(o); /* may create a newer upval after this one */
|
||||
pp = &p->next;
|
||||
}
|
||||
/* not found: create a new one */
|
||||
|
@ -145,13 +142,6 @@ void luaF_freeproto (lua_State *L, Proto *f) {
|
|||
}
|
||||
|
||||
|
||||
void luaF_freeclosure (lua_State *L, Closure *c) {
|
||||
int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
|
||||
sizeLclosure(c->l.nupvalues);
|
||||
luaM_freemem(L, c, size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Look for n-th local variable at line `line' in function `func'.
|
||||
** Returns NULL if not found.
|
||||
|
|
|
@ -19,12 +19,11 @@
|
|||
|
||||
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
|
||||
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
|
||||
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p);
|
||||
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
|
||||
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
|
||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c);
|
||||
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
int pc);
|
||||
|
|
511
src/lua/lgc.cpp
511
src/lua/lgc.cpp
|
@ -23,34 +23,31 @@
|
|||
|
||||
|
||||
|
||||
/* how much to allocate before next GC step */
|
||||
#define GCSTEPSIZE 1024
|
||||
/*
|
||||
** cost of sweeping one element (the size of a small object divided
|
||||
** by some adjust for the sweep speed)
|
||||
*/
|
||||
#define GCSWEEPCOST ((sizeof(TString) + 4) / 4)
|
||||
|
||||
/* maximum number of elements to sweep in each single step */
|
||||
#define GCSWEEPMAX 40
|
||||
|
||||
/* cost of sweeping one element */
|
||||
#define GCSWEEPCOST 1
|
||||
#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
|
||||
|
||||
/* maximum number of finalizers to call in each GC step */
|
||||
#define GCFINALIZENUM 4
|
||||
|
||||
/* cost of marking the root set */
|
||||
#define GCROOTCOST 10
|
||||
|
||||
/* cost of atomic step */
|
||||
#define GCATOMICCOST 1000
|
||||
|
||||
/* basic cost to traverse one object (to be added to the links the
|
||||
object may have) */
|
||||
#define TRAVCOST 5
|
||||
/*
|
||||
** macro to adjust 'stepmul': 'stepmul' is actually used like
|
||||
** 'stepmul / STEPMULADJ' (value chosen by tests)
|
||||
*/
|
||||
#define STEPMULADJ 200
|
||||
|
||||
|
||||
/*
|
||||
** standard negative debt for GC; a reasonable "time" to wait before
|
||||
** starting a new cycle
|
||||
** macro to adjust 'pause': 'pause' is actually used like
|
||||
** 'pause / PAUSEADJ' (value chosen by tests)
|
||||
*/
|
||||
#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause)
|
||||
#define PAUSEADJ 100
|
||||
|
||||
|
||||
/*
|
||||
|
@ -64,8 +61,6 @@
|
|||
#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS)
|
||||
#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
|
||||
|
||||
#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS)))
|
||||
|
||||
|
||||
#define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT)
|
||||
|
||||
|
@ -122,10 +117,10 @@ static void removeentry (Node *n) {
|
|||
** other objects: if really collected, cannot keep them; for objects
|
||||
** being finalized, keep them in keys, but not in values
|
||||
*/
|
||||
static int iscleared (const TValue *o) {
|
||||
static int iscleared (global_State *g, const TValue *o) {
|
||||
if (!iscollectable(o)) return 0;
|
||||
else if (ttisstring(o)) {
|
||||
stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */
|
||||
markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */
|
||||
return 0;
|
||||
}
|
||||
else return iswhite(gcvalue(o));
|
||||
|
@ -139,9 +134,9 @@ static int iscleared (const TValue *o) {
|
|||
void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
|
||||
global_State *g = G(L);
|
||||
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
||||
lua_assert(isgenerational(g) || g->gcstate != GCSpause);
|
||||
lua_assert(g->gcstate != GCSpause);
|
||||
lua_assert(gch(o)->tt != LUA_TTABLE);
|
||||
if (keepinvariant(g)) /* must keep invariant? */
|
||||
if (keepinvariantout(g)) /* must keep invariant? */
|
||||
reallymarkobject(g, v); /* restore invariant */
|
||||
else { /* sweep phase */
|
||||
lua_assert(issweepphase(g));
|
||||
|
@ -216,7 +211,8 @@ void luaC_checkupvalcolor (global_State *g, UpVal *uv) {
|
|||
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
|
||||
int offset) {
|
||||
global_State *g = G(L);
|
||||
GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
|
||||
char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz));
|
||||
GCObject *o = obj2gco(raw + offset);
|
||||
if (list == NULL)
|
||||
list = &g->allgc; /* standard list for collectable objects */
|
||||
gch(o)->marked = luaC_white(g);
|
||||
|
@ -238,54 +234,63 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
|
|||
|
||||
|
||||
/*
|
||||
** mark an object. Userdata and closed upvalues are visited and turned
|
||||
** black here. Strings remain gray (it is the same as making them
|
||||
** black). Other objects are marked gray and added to appropriate list
|
||||
** to be visited (and turned black) later. (Open upvalues are already
|
||||
** linked in 'headuv' list.)
|
||||
** mark an object. Userdata, strings, and closed upvalues are visited
|
||||
** and turned black here. Other objects are marked gray and added
|
||||
** to appropriate list to be visited (and turned black) later. (Open
|
||||
** upvalues are already linked in 'headuv' list.)
|
||||
*/
|
||||
static void reallymarkobject (global_State *g, GCObject *o) {
|
||||
lua_assert(iswhite(o) && !isdead(g, o));
|
||||
lu_mem size;
|
||||
white2gray(o);
|
||||
switch (gch(o)->tt) {
|
||||
case LUA_TSTRING: {
|
||||
return; /* for strings, gray is as good as black */
|
||||
case LUA_TSHRSTR:
|
||||
case LUA_TLNGSTR: {
|
||||
size = sizestring(gco2ts(o));
|
||||
break; /* nothing else to mark; make it black */
|
||||
}
|
||||
case LUA_TUSERDATA: {
|
||||
Table *mt = gco2u(o)->metatable;
|
||||
markobject(g, mt);
|
||||
markobject(g, gco2u(o)->env);
|
||||
gray2black(o); /* all pointers marked */
|
||||
return;
|
||||
size = sizeudata(gco2u(o));
|
||||
break;
|
||||
}
|
||||
case LUA_TUPVAL: {
|
||||
UpVal *uv = gco2uv(o);
|
||||
markvalue(g, uv->v);
|
||||
if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */
|
||||
gray2black(o); /* make it black */
|
||||
if (uv->v != &uv->u.value) /* open? */
|
||||
return; /* open upvalues remain gray */
|
||||
size = sizeof(UpVal);
|
||||
break;
|
||||
}
|
||||
case LUA_TLCL: {
|
||||
gco2lcl(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
return;
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
gco2cl(o)->c.gclist = g->gray;
|
||||
case LUA_TCCL: {
|
||||
gco2ccl(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case LUA_TTABLE: {
|
||||
linktable(gco2t(o), &g->gray);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case LUA_TTHREAD: {
|
||||
gco2th(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case LUA_TPROTO: {
|
||||
gco2p(o)->gclist = g->gray;
|
||||
g->gray = o;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
default: lua_assert(0);
|
||||
default: lua_assert(0); return;
|
||||
}
|
||||
gray2black(o);
|
||||
g->GCmemtrav += size;
|
||||
}
|
||||
|
||||
|
||||
|
@ -328,7 +333,7 @@ static void remarkupvals (global_State *g) {
|
|||
** mark root set and reset all gray lists, to start a new
|
||||
** incremental (or full) collection
|
||||
*/
|
||||
static void markroot (global_State *g) {
|
||||
static void restartcollection (global_State *g) {
|
||||
g->gray = g->grayagain = NULL;
|
||||
g->weak = g->allweak = g->ephemeron = NULL;
|
||||
markobject(g, g->mainthread);
|
||||
|
@ -358,7 +363,7 @@ static void traverseweakvalue (global_State *g, Table *h) {
|
|||
else {
|
||||
lua_assert(!ttisnil(gkey(n)));
|
||||
markvalue(g, gkey(n)); /* mark key */
|
||||
if (!hasclears && iscleared(gval(n))) /* is there a white value? */
|
||||
if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */
|
||||
hasclears = 1; /* table will have to be cleared */
|
||||
}
|
||||
}
|
||||
|
@ -387,7 +392,7 @@ static int traverseephemeron (global_State *g, Table *h) {
|
|||
checkdeadkey(n);
|
||||
if (ttisnil(gval(n))) /* entry is empty? */
|
||||
removeentry(n); /* remove it */
|
||||
else if (iscleared(gkey(n))) { /* key is not marked (yet)? */
|
||||
else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */
|
||||
hasclears = 1; /* table must be cleared */
|
||||
if (valiswhite(gval(n))) /* value not marked yet? */
|
||||
prop = 1; /* must propagate again */
|
||||
|
@ -425,30 +430,26 @@ static void traversestrongtable (global_State *g, Table *h) {
|
|||
}
|
||||
|
||||
|
||||
static int traversetable (global_State *g, Table *h) {
|
||||
static lu_mem traversetable (global_State *g, Table *h) {
|
||||
const char *weakkey, *weakvalue;
|
||||
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
|
||||
markobject(g, h->metatable);
|
||||
if (mode && ttisstring(mode)) { /* is there a weak mode? */
|
||||
int weakkey = (strchr(svalue(mode), 'k') != NULL);
|
||||
int weakvalue = (strchr(svalue(mode), 'v') != NULL);
|
||||
if (weakkey || weakvalue) { /* is really weak? */
|
||||
black2gray(obj2gco(h)); /* keep table gray */
|
||||
if (!weakkey) { /* strong keys? */
|
||||
traverseweakvalue(g, h);
|
||||
return TRAVCOST + sizenode(h);
|
||||
}
|
||||
else if (!weakvalue) { /* strong values? */
|
||||
traverseephemeron(g, h);
|
||||
return TRAVCOST + h->sizearray + sizenode(h);
|
||||
}
|
||||
else {
|
||||
linktable(h, &g->allweak); /* nothing to traverse now */
|
||||
return TRAVCOST;
|
||||
}
|
||||
} /* else go through */
|
||||
if (mode && ttisstring(mode) && /* is there a weak mode? */
|
||||
((weakkey = strchr(svalue(mode), 'k')),
|
||||
(weakvalue = strchr(svalue(mode), 'v')),
|
||||
(weakkey || weakvalue))) { /* is really weak? */
|
||||
black2gray(obj2gco(h)); /* keep table gray */
|
||||
if (!weakkey) /* strong keys? */
|
||||
traverseweakvalue(g, h);
|
||||
else if (!weakvalue) /* strong values? */
|
||||
traverseephemeron(g, h);
|
||||
else /* all weak */
|
||||
linktable(h, &g->allweak); /* nothing to traverse now */
|
||||
}
|
||||
traversestrongtable(g, h);
|
||||
return TRAVCOST + h->sizearray + (2 * sizenode(h));
|
||||
else /* not weak */
|
||||
traversestrongtable(g, h);
|
||||
return sizeof(Table) + sizeof(TValue) * h->sizearray +
|
||||
sizeof(Node) * cast(size_t, sizenode(h));
|
||||
}
|
||||
|
||||
|
||||
|
@ -456,86 +457,108 @@ static int traverseproto (global_State *g, Proto *f) {
|
|||
int i;
|
||||
if (f->cache && iswhite(obj2gco(f->cache)))
|
||||
f->cache = NULL; /* allow cache to be collected */
|
||||
stringmark(f->source);
|
||||
markobject(g, f->source);
|
||||
for (i = 0; i < f->sizek; i++) /* mark literals */
|
||||
markvalue(g, &f->k[i]);
|
||||
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
|
||||
stringmark(f->upvalues[i].name);
|
||||
markobject(g, f->upvalues[i].name);
|
||||
for (i = 0; i < f->sizep; i++) /* mark nested protos */
|
||||
markobject(g, f->p[i]);
|
||||
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
|
||||
stringmark(f->locvars[i].varname);
|
||||
return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
|
||||
markobject(g, f->locvars[i].varname);
|
||||
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
|
||||
sizeof(Proto *) * f->sizep +
|
||||
sizeof(TValue) * f->sizek +
|
||||
sizeof(int) * f->sizelineinfo +
|
||||
sizeof(LocVar) * f->sizelocvars +
|
||||
sizeof(Upvaldesc) * f->sizeupvalues;
|
||||
}
|
||||
|
||||
|
||||
static int traverseclosure (global_State *g, Closure *cl) {
|
||||
if (cl->c.isC) {
|
||||
int i;
|
||||
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
|
||||
markvalue(g, &cl->c.upvalue[i]);
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
|
||||
markobject(g, cl->l.p); /* mark its prototype */
|
||||
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */
|
||||
markobject(g, cl->l.upvals[i]);
|
||||
}
|
||||
return TRAVCOST + cl->c.nupvalues;
|
||||
static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
|
||||
int i;
|
||||
for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
|
||||
markvalue(g, &cl->upvalue[i]);
|
||||
return sizeCclosure(cl->nupvalues);
|
||||
}
|
||||
|
||||
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
|
||||
int i;
|
||||
markobject(g, cl->p); /* mark its prototype */
|
||||
for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
|
||||
markobject(g, cl->upvals[i]);
|
||||
return sizeLclosure(cl->nupvalues);
|
||||
}
|
||||
|
||||
|
||||
static int traversestack (global_State *g, lua_State *L) {
|
||||
StkId o = L->stack;
|
||||
static lu_mem traversestack (global_State *g, lua_State *th) {
|
||||
int n = 0;
|
||||
StkId o = th->stack;
|
||||
if (o == NULL)
|
||||
return 1; /* stack not completely built yet */
|
||||
for (; o < L->top; o++)
|
||||
for (; o < th->top; o++) /* mark live elements in the stack */
|
||||
markvalue(g, o);
|
||||
if (g->gcstate == GCSatomic) { /* final traversal? */
|
||||
StkId lim = L->stack + L->stacksize; /* real end of stack */
|
||||
StkId lim = th->stack + th->stacksize; /* real end of stack */
|
||||
for (; o < lim; o++) /* clear not-marked stack slice */
|
||||
setnilvalue(o);
|
||||
}
|
||||
return TRAVCOST + cast_int(o - L->stack);
|
||||
else { /* count call infos to compute size */
|
||||
CallInfo *ci;
|
||||
for (ci = &th->base_ci; ci != th->ci; ci = ci->next)
|
||||
n++;
|
||||
}
|
||||
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
|
||||
sizeof(CallInfo) * n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** traverse one gray object, turning it to black (except for threads,
|
||||
** which are always gray).
|
||||
** Returns number of values traversed.
|
||||
*/
|
||||
static int propagatemark (global_State *g) {
|
||||
static void propagatemark (global_State *g) {
|
||||
lu_mem size;
|
||||
GCObject *o = g->gray;
|
||||
lua_assert(isgray(o));
|
||||
gray2black(o);
|
||||
switch (gch(o)->tt) {
|
||||
case LUA_TTABLE: {
|
||||
Table *h = gco2t(o);
|
||||
g->gray = h->gclist;
|
||||
return traversetable(g, h);
|
||||
g->gray = h->gclist; /* remove from 'gray' list */
|
||||
size = traversetable(g, h);
|
||||
break;
|
||||
}
|
||||
case LUA_TFUNCTION: {
|
||||
Closure *cl = gco2cl(o);
|
||||
g->gray = cl->c.gclist;
|
||||
return traverseclosure(g, cl);
|
||||
case LUA_TLCL: {
|
||||
LClosure *cl = gco2lcl(o);
|
||||
g->gray = cl->gclist; /* remove from 'gray' list */
|
||||
size = traverseLclosure(g, cl);
|
||||
break;
|
||||
}
|
||||
case LUA_TCCL: {
|
||||
CClosure *cl = gco2ccl(o);
|
||||
g->gray = cl->gclist; /* remove from 'gray' list */
|
||||
size = traverseCclosure(g, cl);
|
||||
break;
|
||||
}
|
||||
case LUA_TTHREAD: {
|
||||
lua_State *th = gco2th(o);
|
||||
g->gray = th->gclist;
|
||||
g->gray = th->gclist; /* remove from 'gray' list */
|
||||
th->gclist = g->grayagain;
|
||||
g->grayagain = o;
|
||||
g->grayagain = o; /* insert into 'grayagain' list */
|
||||
black2gray(o);
|
||||
return traversestack(g, th);
|
||||
size = traversestack(g, th);
|
||||
break;
|
||||
}
|
||||
case LUA_TPROTO: {
|
||||
Proto *p = gco2p(o);
|
||||
g->gray = p->gclist;
|
||||
return traverseproto(g, p);
|
||||
g->gray = p->gclist; /* remove from 'gray' list */
|
||||
size = traverseproto(g, p);
|
||||
break;
|
||||
}
|
||||
default: lua_assert(0); return 0;
|
||||
default: lua_assert(0); return;
|
||||
}
|
||||
g->GCmemtrav += size;
|
||||
}
|
||||
|
||||
|
||||
|
@ -598,12 +621,12 @@ static void convergeephemerons (global_State *g) {
|
|||
** clear entries with unmarked keys from all weaktables in list 'l' up
|
||||
** to element 'f'
|
||||
*/
|
||||
static void clearkeys (GCObject *l, GCObject *f) {
|
||||
static void clearkeys (global_State *g, GCObject *l, GCObject *f) {
|
||||
for (; l != f; l = gco2t(l)->gclist) {
|
||||
Table *h = gco2t(l);
|
||||
Node *n, *limit = gnodelast(h);
|
||||
for (n = gnode(h, 0); n < limit; n++) {
|
||||
if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) {
|
||||
if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
|
||||
setnilvalue(gval(n)); /* remove value ... */
|
||||
removeentry(n); /* and remove entry from table */
|
||||
}
|
||||
|
@ -616,18 +639,18 @@ static void clearkeys (GCObject *l, GCObject *f) {
|
|||
** clear entries with unmarked values from all weaktables in list 'l' up
|
||||
** to element 'f'
|
||||
*/
|
||||
static void clearvalues (GCObject *l, GCObject *f) {
|
||||
static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
|
||||
for (; l != f; l = gco2t(l)->gclist) {
|
||||
Table *h = gco2t(l);
|
||||
Node *n, *limit = gnodelast(h);
|
||||
int i;
|
||||
for (i = 0; i < h->sizearray; i++) {
|
||||
TValue *o = &h->array[i];
|
||||
if (iscleared(o)) /* value was collected? */
|
||||
if (iscleared(g, o)) /* value was collected? */
|
||||
setnilvalue(o); /* remove value */
|
||||
}
|
||||
for (n = gnode(h, 0); n < limit; n++) {
|
||||
if (!ttisnil(gval(n)) && iscleared(gval(n))) {
|
||||
if (!ttisnil(gval(n)) && iscleared(g, gval(n))) {
|
||||
setnilvalue(gval(n)); /* remove value ... */
|
||||
removeentry(n); /* and remove entry from table */
|
||||
}
|
||||
|
@ -639,13 +662,22 @@ static void clearvalues (GCObject *l, GCObject *f) {
|
|||
static void freeobj (lua_State *L, GCObject *o) {
|
||||
switch (gch(o)->tt) {
|
||||
case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
|
||||
case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
|
||||
case LUA_TLCL: {
|
||||
luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues));
|
||||
break;
|
||||
}
|
||||
case LUA_TCCL: {
|
||||
luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
|
||||
break;
|
||||
}
|
||||
case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
|
||||
case LUA_TTABLE: luaH_free(L, gco2t(o)); break;
|
||||
case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break;
|
||||
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
|
||||
case LUA_TSTRING: {
|
||||
case LUA_TSHRSTR:
|
||||
G(L)->strt.nuse--;
|
||||
/* go through */
|
||||
case LUA_TLNGSTR: {
|
||||
luaM_freemem(L, o, sizestring(gco2ts(o)));
|
||||
break;
|
||||
}
|
||||
|
@ -688,7 +720,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
|||
int ow = otherwhite(g);
|
||||
int toclear, toset; /* bits to clear and to set in all live objects */
|
||||
int tostop; /* stop sweep when this is true */
|
||||
l_mem debt = g->GCdebt; /* current debt */
|
||||
if (isgenerational(g)) { /* generational mode? */
|
||||
toclear = ~0; /* clear nothing */
|
||||
toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */
|
||||
|
@ -707,19 +738,30 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
|||
freeobj(L, curr); /* erase 'curr' */
|
||||
}
|
||||
else {
|
||||
if (testbits(marked, tostop))
|
||||
return NULL; /* stop sweeping this list */
|
||||
if (gch(curr)->tt == LUA_TTHREAD)
|
||||
sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */
|
||||
if (testbits(marked, tostop)) {
|
||||
static GCObject *nullp = NULL;
|
||||
p = &nullp; /* stop sweeping this list */
|
||||
break;
|
||||
}
|
||||
/* update marks */
|
||||
gch(curr)->marked = cast_byte((marked & toclear) | toset);
|
||||
p = &gch(curr)->next; /* go to next element */
|
||||
}
|
||||
}
|
||||
luaE_setdebt(g, debt); /* sweeping should not change debt */
|
||||
return (*p == NULL) ? NULL : p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** sweep a list until a live object (or end of list)
|
||||
*/
|
||||
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
|
||||
GCObject ** old = p;
|
||||
int i = 0;
|
||||
do {
|
||||
i++;
|
||||
p = sweeplist(L, p, 1);
|
||||
} while (p == old);
|
||||
if (n) *n += i;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -751,7 +793,7 @@ static GCObject *udata2finalize (global_State *g) {
|
|||
g->allgc = o;
|
||||
resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */
|
||||
lua_assert(!isold(o)); /* see MOVE OLD rule */
|
||||
if (!keepinvariant(g)) /* not keeping invariant? */
|
||||
if (!keepinvariantout(g)) /* not keeping invariant? */
|
||||
makewhite(g, o); /* "sweep" object */
|
||||
return o;
|
||||
}
|
||||
|
@ -782,12 +824,14 @@ static void GCTM (lua_State *L, int propagateerrors) {
|
|||
L->allowhook = oldah; /* restore hooks */
|
||||
g->gcrunning = running; /* restore state */
|
||||
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
|
||||
if (status == LUA_ERRRUN) { /* is there an error msg.? */
|
||||
luaO_pushfstring(L, "error in __gc metamethod (%s)",
|
||||
lua_tostring(L, -1));
|
||||
if (status == LUA_ERRRUN) { /* is there an error object? */
|
||||
const char *msg = (ttisstring(L->top - 1))
|
||||
? svalue(L->top - 1)
|
||||
: "no message";
|
||||
luaO_pushfstring(L, "error in __gc metamethod (%s)", msg);
|
||||
status = LUA_ERRGCMM; /* error in __gc metamethod */
|
||||
}
|
||||
luaD_throw(L, status); /* re-send error */
|
||||
luaD_throw(L, status); /* re-throw error */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -808,7 +852,7 @@ static void separatetobefnz (lua_State *L, int all) {
|
|||
while ((curr = *p) != NULL) { /* traverse all finalizable objects */
|
||||
lua_assert(!isfinalized(curr));
|
||||
lua_assert(testbit(gch(curr)->marked, SEPARATED));
|
||||
if (!(all || iswhite(curr))) /* not being collected? */
|
||||
if (!(iswhite(curr) || all)) /* not being collected? */
|
||||
p = &gch(curr)->next; /* don't bother with it */
|
||||
else {
|
||||
l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
|
||||
|
@ -833,12 +877,21 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
|||
return; /* nothing to be done */
|
||||
else { /* move 'o' to 'finobj' list */
|
||||
GCObject **p;
|
||||
for (p = &g->allgc; *p != o; p = &gch(*p)->next) ;
|
||||
*p = gch(o)->next; /* remove 'o' from root list */
|
||||
gch(o)->next = g->finobj; /* link it in list 'finobj' */
|
||||
GCheader *ho = gch(o);
|
||||
if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */
|
||||
lua_assert(issweepphase(g));
|
||||
g->sweepgc = sweeptolive(L, g->sweepgc, NULL);
|
||||
}
|
||||
/* search for pointer pointing to 'o' */
|
||||
for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ }
|
||||
*p = ho->next; /* remove 'o' from root list */
|
||||
ho->next = g->finobj; /* link it in list 'finobj' */
|
||||
g->finobj = o;
|
||||
l_setbit(gch(o)->marked, SEPARATED); /* mark it as such */
|
||||
resetoldbit(o); /* see MOVE OLD rule */
|
||||
l_setbit(ho->marked, SEPARATED); /* mark it as such */
|
||||
if (!keepinvariantout(g)) /* not keeping invariant? */
|
||||
makewhite(g, o); /* "sweep" object */
|
||||
else
|
||||
resetoldbit(o); /* see MOVE OLD rule */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -852,9 +905,46 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
|||
*/
|
||||
|
||||
|
||||
/*
|
||||
** set a reasonable "time" to wait before starting a new GC cycle;
|
||||
** cycle will start when memory use hits threshold
|
||||
*/
|
||||
static void setpause (global_State *g, l_mem estimate) {
|
||||
l_mem debt, threshold;
|
||||
estimate = estimate / PAUSEADJ; /* adjust 'estimate' */
|
||||
threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */
|
||||
? estimate * g->gcpause /* no overflow */
|
||||
: MAX_LMEM; /* overflow; truncate to maximum */
|
||||
debt = -cast(l_mem, threshold - gettotalbytes(g));
|
||||
luaE_setdebt(g, debt);
|
||||
}
|
||||
|
||||
|
||||
#define sweepphases \
|
||||
(bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep))
|
||||
|
||||
|
||||
/*
|
||||
** enter first sweep phase (strings) and prepare pointers for other
|
||||
** sweep phases. The calls to 'sweeptolive' make pointers point to an
|
||||
** object inside the list (instead of to the header), so that the real
|
||||
** sweep do not need to skip objects created between "now" and the start
|
||||
** of the real sweep.
|
||||
** Returns how many objects it swept.
|
||||
*/
|
||||
static int entersweep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
int n = 0;
|
||||
g->gcstate = GCSsweepstring;
|
||||
lua_assert(g->sweepgc == NULL && g->sweepfin == NULL);
|
||||
/* prepare to sweep strings, finalizable objects, and regular objects */
|
||||
g->sweepstrgc = 0;
|
||||
g->sweepfin = sweeptolive(L, &g->finobj, &n);
|
||||
g->sweepgc = sweeptolive(L, &g->allgc, &n);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** change GC mode
|
||||
*/
|
||||
|
@ -864,15 +954,14 @@ void luaC_changemode (lua_State *L, int mode) {
|
|||
if (mode == KGC_GEN) { /* change to generational mode */
|
||||
/* make sure gray lists are consistent */
|
||||
luaC_runtilstate(L, bitmask(GCSpropagate));
|
||||
g->lastmajormem = gettotalbytes(g);
|
||||
g->GCestimate = gettotalbytes(g);
|
||||
g->gckind = KGC_GEN;
|
||||
}
|
||||
else { /* change to incremental mode */
|
||||
/* sweep all objects to turn them back to white
|
||||
(as white has not changed, nothing extra will be collected) */
|
||||
g->sweepstrgc = 0;
|
||||
g->gcstate = GCSsweepstring;
|
||||
g->gckind = KGC_NORMAL;
|
||||
entersweep(L);
|
||||
luaC_runtilstate(L, ~sweepphases);
|
||||
}
|
||||
}
|
||||
|
@ -906,8 +995,9 @@ void luaC_freeallobjects (lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
static void atomic (lua_State *L) {
|
||||
static l_mem atomic (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */
|
||||
GCObject *origweak, *origall;
|
||||
lua_assert(!iswhite(obj2gco(g->mainthread)));
|
||||
markobject(g, L); /* mark running thread */
|
||||
|
@ -916,77 +1006,85 @@ static void atomic (lua_State *L) {
|
|||
markmt(g); /* mark basic metatables */
|
||||
/* remark occasional upvalues of (maybe) dead threads */
|
||||
remarkupvals(g);
|
||||
propagateall(g); /* propagate changes */
|
||||
work += g->GCmemtrav; /* stop counting (do not (re)count grays) */
|
||||
/* traverse objects caught by write barrier and by 'remarkupvals' */
|
||||
retraversegrays(g);
|
||||
work -= g->GCmemtrav; /* restart counting */
|
||||
convergeephemerons(g);
|
||||
/* at this point, all strongly accessible objects are marked. */
|
||||
/* clear values from weak tables, before checking finalizers */
|
||||
clearvalues(g->weak, NULL);
|
||||
clearvalues(g->allweak, NULL);
|
||||
clearvalues(g, g->weak, NULL);
|
||||
clearvalues(g, g->allweak, NULL);
|
||||
origweak = g->weak; origall = g->allweak;
|
||||
work += g->GCmemtrav; /* stop counting (objects being finalized) */
|
||||
separatetobefnz(L, 0); /* separate objects to be finalized */
|
||||
markbeingfnz(g); /* mark userdata that will be finalized */
|
||||
markbeingfnz(g); /* mark objects that will be finalized */
|
||||
propagateall(g); /* remark, to propagate `preserveness' */
|
||||
work -= g->GCmemtrav; /* restart counting */
|
||||
convergeephemerons(g);
|
||||
/* at this point, all resurrected objects are marked. */
|
||||
/* remove dead objects from weak tables */
|
||||
clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */
|
||||
clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */
|
||||
clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */
|
||||
clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */
|
||||
/* clear values from resurrected weak tables */
|
||||
clearvalues(g->weak, origweak);
|
||||
clearvalues(g->allweak, origall);
|
||||
g->sweepstrgc = 0; /* prepare to sweep strings */
|
||||
g->gcstate = GCSsweepstring;
|
||||
clearvalues(g, g->weak, origweak);
|
||||
clearvalues(g, g->allweak, origall);
|
||||
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
|
||||
/*lua_checkmemory(L);*/
|
||||
work += g->GCmemtrav; /* complete counting */
|
||||
return work; /* estimate of memory marked by 'atomic' */
|
||||
}
|
||||
|
||||
|
||||
static l_mem singlestep (lua_State *L) {
|
||||
static lu_mem singlestep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
switch (g->gcstate) {
|
||||
case GCSpause: {
|
||||
if (!isgenerational(g))
|
||||
markroot(g); /* start a new collection */
|
||||
/* in any case, root must be marked */
|
||||
lua_assert(!iswhite(obj2gco(g->mainthread))
|
||||
&& !iswhite(gcvalue(&g->l_registry)));
|
||||
/* start to count memory traversed */
|
||||
g->GCmemtrav = g->strt.size * sizeof(GCObject*);
|
||||
lua_assert(!isgenerational(g));
|
||||
restartcollection(g);
|
||||
g->gcstate = GCSpropagate;
|
||||
return GCROOTCOST;
|
||||
return g->GCmemtrav;
|
||||
}
|
||||
case GCSpropagate: {
|
||||
if (g->gray)
|
||||
return propagatemark(g);
|
||||
if (g->gray) {
|
||||
lu_mem oldtrav = g->GCmemtrav;
|
||||
propagatemark(g);
|
||||
return g->GCmemtrav - oldtrav; /* memory traversed in this step */
|
||||
}
|
||||
else { /* no more `gray' objects */
|
||||
lu_mem work;
|
||||
int sw;
|
||||
g->gcstate = GCSatomic; /* finish mark phase */
|
||||
atomic(L);
|
||||
return GCATOMICCOST;
|
||||
g->GCestimate = g->GCmemtrav; /* save what was counted */;
|
||||
work = atomic(L); /* add what was traversed by 'atomic' */
|
||||
g->GCestimate += work; /* estimate of total memory traversed */
|
||||
sw = entersweep(L);
|
||||
return work + sw * GCSWEEPCOST;
|
||||
}
|
||||
}
|
||||
case GCSsweepstring: {
|
||||
if (g->sweepstrgc < g->strt.size) {
|
||||
sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
|
||||
return GCSWEEPCOST;
|
||||
}
|
||||
else { /* no more strings to sweep */
|
||||
g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */
|
||||
int i;
|
||||
for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
|
||||
sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
|
||||
g->sweepstrgc += i;
|
||||
if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */
|
||||
g->gcstate = GCSsweepudata;
|
||||
return 0;
|
||||
}
|
||||
return i * GCSWEEPCOST;
|
||||
}
|
||||
case GCSsweepudata: {
|
||||
if (*g->sweepgc) {
|
||||
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
|
||||
if (g->sweepfin) {
|
||||
g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX);
|
||||
return GCSWEEPMAX*GCSWEEPCOST;
|
||||
}
|
||||
else {
|
||||
g->sweepgc = &g->allgc; /* go to next phase */
|
||||
g->gcstate = GCSsweep;
|
||||
return GCSWEEPCOST;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
case GCSsweep: {
|
||||
if (*g->sweepgc) {
|
||||
if (g->sweepgc) {
|
||||
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
|
||||
return GCSWEEPMAX*GCSWEEPCOST;
|
||||
}
|
||||
|
@ -1017,43 +1115,58 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
|
|||
|
||||
static void generationalcollection (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if (g->lastmajormem == 0) { /* signal for another major collection? */
|
||||
lua_assert(g->gcstate == GCSpropagate);
|
||||
if (g->GCestimate == 0) { /* signal for another major collection? */
|
||||
luaC_fullgc(L, 0); /* perform a full regular collection */
|
||||
g->lastmajormem = gettotalbytes(g); /* update control */
|
||||
g->GCestimate = gettotalbytes(g); /* update control */
|
||||
}
|
||||
else {
|
||||
luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */
|
||||
luaC_runtilstate(L, bitmask(GCSpause));
|
||||
if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc)
|
||||
g->lastmajormem = 0; /* signal for a major collection */
|
||||
lu_mem estimate = g->GCestimate;
|
||||
luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */
|
||||
g->gcstate = GCSpropagate; /* skip restart */
|
||||
if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc)
|
||||
g->GCestimate = 0; /* signal for a major collection */
|
||||
else
|
||||
g->GCestimate = estimate; /* keep estimate from last major coll. */
|
||||
|
||||
}
|
||||
luaE_setdebt(g, stddebt(g));
|
||||
setpause(g, gettotalbytes(g));
|
||||
lua_assert(g->gcstate == GCSpropagate);
|
||||
}
|
||||
|
||||
|
||||
static void step (lua_State *L) {
|
||||
static void incstep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
l_mem lim = g->gcstepmul; /* how much to work */
|
||||
l_mem debt = g->GCdebt;
|
||||
int stepmul = g->gcstepmul;
|
||||
if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */
|
||||
/* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
|
||||
debt = (debt / STEPMULADJ) + 1;
|
||||
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
|
||||
do { /* always perform at least one single step */
|
||||
lim -= singlestep(L);
|
||||
} while (lim > 0 && g->gcstate != GCSpause);
|
||||
if (g->gcstate != GCSpause)
|
||||
luaE_setdebt(g, g->GCdebt - GCSTEPSIZE);
|
||||
else
|
||||
luaE_setdebt(g, stddebt(g));
|
||||
lu_mem work = singlestep(L); /* do some work */
|
||||
debt -= work;
|
||||
} while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
|
||||
if (g->gcstate == GCSpause)
|
||||
setpause(g, g->GCestimate); /* pause until next cycle */
|
||||
else {
|
||||
debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */
|
||||
luaE_setdebt(g, debt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** performs a basic GC step even if the collector is stopped
|
||||
** performs a basic GC step
|
||||
*/
|
||||
void luaC_forcestep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
int i;
|
||||
if (isgenerational(g)) generationalcollection(L);
|
||||
else step(L);
|
||||
for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++)
|
||||
GCTM(L, 1); /* Call a few pending finalizers */
|
||||
else incstep(L);
|
||||
/* run a few finalizers (or all of them at the end of a collect cycle) */
|
||||
for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
|
||||
GCTM(L, 1); /* call one finalizer */
|
||||
}
|
||||
|
||||
|
||||
|
@ -1061,10 +1174,13 @@ void luaC_forcestep (lua_State *L) {
|
|||
** performs a basic GC step only if collector is running
|
||||
*/
|
||||
void luaC_step (lua_State *L) {
|
||||
if (G(L)->gcrunning) luaC_forcestep(L);
|
||||
global_State *g = G(L);
|
||||
if (g->gcrunning) luaC_forcestep(L);
|
||||
else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** performs a full GC cycle; if "isemergency", does not call
|
||||
** finalizers (which could change stack positions)
|
||||
|
@ -1073,26 +1189,27 @@ void luaC_fullgc (lua_State *L, int isemergency) {
|
|||
global_State *g = G(L);
|
||||
int origkind = g->gckind;
|
||||
lua_assert(origkind != KGC_EMERGENCY);
|
||||
if (!isemergency) /* do not run finalizers during emergency GC */
|
||||
if (isemergency) /* do not run finalizers during emergency GC */
|
||||
g->gckind = KGC_EMERGENCY;
|
||||
else {
|
||||
g->gckind = KGC_NORMAL;
|
||||
callallpendingfinalizers(L, 1);
|
||||
if (keepinvariant(g)) { /* marking phase? */
|
||||
}
|
||||
if (keepinvariant(g)) { /* may there be some black objects? */
|
||||
/* must sweep all objects to turn them back to white
|
||||
(as white has not changed, nothing will be collected) */
|
||||
g->sweepstrgc = 0;
|
||||
g->gcstate = GCSsweepstring;
|
||||
entersweep(L);
|
||||
}
|
||||
g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL;
|
||||
/* finish any pending sweep phase to start a new cycle */
|
||||
luaC_runtilstate(L, bitmask(GCSpause));
|
||||
/* run entire collector */
|
||||
luaC_runtilstate(L, ~bitmask(GCSpause));
|
||||
luaC_runtilstate(L, bitmask(GCSpause));
|
||||
luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */
|
||||
luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */
|
||||
if (origkind == KGC_GEN) { /* generational mode? */
|
||||
/* generational mode must always start in propagate phase */
|
||||
/* generational mode must be kept in propagate phase */
|
||||
luaC_runtilstate(L, bitmask(GCSpropagate));
|
||||
}
|
||||
g->gckind = origkind;
|
||||
luaE_setdebt(g, stddebt(g));
|
||||
setpause(g, gettotalbytes(g));
|
||||
if (!isemergency) /* do not run finalizers during emergency GC */
|
||||
callallpendingfinalizers(L, 1);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,14 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
/* how much to allocate before next GC step */
|
||||
#if !defined(GCSTEPSIZE)
|
||||
/* ~100 small strings */
|
||||
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Possible states of the Garbage Collector
|
||||
*/
|
||||
|
@ -41,14 +49,24 @@
|
|||
#define isgenerational(g) ((g)->gckind == KGC_GEN)
|
||||
|
||||
/*
|
||||
** macro to tell when main invariant (white objects cannot point to black
|
||||
** macros to tell when main invariant (white objects cannot point to black
|
||||
** ones) must be kept. During a non-generational collection, the sweep
|
||||
** phase may break the invariant, as objects turned white may point to
|
||||
** still-black objects. The invariant is restored when sweep ends and
|
||||
** all objects are white again. During a generational collection, the
|
||||
** invariant must be kept all times.
|
||||
*/
|
||||
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
|
||||
|
||||
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
|
||||
|
||||
|
||||
/*
|
||||
** Outside the collector, the state in generational mode is kept in
|
||||
** 'propagate', so 'keepinvariant' is always true.
|
||||
*/
|
||||
#define keepinvariantout(g) \
|
||||
check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \
|
||||
g->gcstate <= GCSatomic)
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
|
||||
/*
|
||||
** POSIX idiosyncrasy!
|
||||
** This definition must come before the inclusion of 'stdio.h'; it
|
||||
** should not affect non-POSIX systems
|
||||
*/
|
||||
#if !defined(_FILE_OFFSET_BITS)
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _LARGEFILE_SOURCE 1
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -28,6 +28,20 @@
|
|||
#include "lualib.h"
|
||||
|
||||
|
||||
#if !defined(lua_checkmode)
|
||||
|
||||
/*
|
||||
** Check whether 'mode' matches '[rwa]%+?b?'.
|
||||
** Change this macro to accept other modes for 'fopen' besides
|
||||
** the standard ones.
|
||||
*/
|
||||
#define lua_checkmode(mode) \
|
||||
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
|
||||
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
|
||||
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
|
||||
(*mode == '\0'))
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
|
@ -65,36 +79,37 @@
|
|||
|
||||
/*
|
||||
** {======================================================
|
||||
** lua_fseek/lua_ftell: configuration for longer offsets
|
||||
** lua_fseek: configuration for longer offsets
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
#if !defined(lua_fseek) /* { */
|
||||
#if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */
|
||||
|
||||
#if defined(LUA_USE_POSIX)
|
||||
#if defined(LUA_USE_POSIX) /* { */
|
||||
|
||||
#define l_fseek(f,o,w) fseeko(f,o,w)
|
||||
#define l_ftell(f) ftello(f)
|
||||
#define l_seeknum off_t
|
||||
|
||||
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
|
||||
&& defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
&& defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
|
||||
/* Windows (but not DDK) and Visual C++ 2005 or higher */
|
||||
|
||||
#define l_fseek(f,o,w) _fseeki64(f,o,w)
|
||||
#define l_ftell(f) _ftelli64(f)
|
||||
#define l_seeknum __int64
|
||||
|
||||
#else
|
||||
#endif /* } */
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
#if !defined(l_fseek) /* default definitions */
|
||||
#define l_fseek(f,o,w) fseek(f,o,w)
|
||||
#define l_ftell(f) ftell(f)
|
||||
#define l_seeknum long
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* } */
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
@ -211,14 +226,8 @@ static int io_open (lua_State *L) {
|
|||
const char *filename = luaL_checkstring(L, 1);
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
LStream *p = newfile(L);
|
||||
int i = 0;
|
||||
/* check whether 'mode' matches '[rwa]%+?b?' */
|
||||
if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL &&
|
||||
(mode[i] != '+' || ++i) && /* skip if char is '+' */
|
||||
(mode[i] != 'b' || ++i) && /* skip if char is 'b' */
|
||||
(mode[i] == '\0')))
|
||||
return luaL_error(L, "invalid mode " LUA_QS
|
||||
" (should match " LUA_QL("[rwa]%%+?b?") ")", mode);
|
||||
const char *md = mode; /* to traverse/check mode */
|
||||
luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
|
||||
p->f = fopen(filename, mode);
|
||||
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
|
||||
}
|
||||
|
|
|
@ -66,22 +66,22 @@ void luaX_init (lua_State *L) {
|
|||
for (i=0; i<NUM_RESERVED; i++) {
|
||||
TString *ts = luaS_new(L, luaX_tokens[i]);
|
||||
luaS_fix(ts); /* reserved words are never collected */
|
||||
ts->tsv.reserved = cast_byte(i+1); /* reserved word */
|
||||
ts->tsv.extra = cast_byte(i+1); /* reserved word */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *luaX_token2str (LexState *ls, int token) {
|
||||
if (token < FIRST_RESERVED - 1) {
|
||||
if (token < FIRST_RESERVED - 1) { /* single-byte symbols? */
|
||||
lua_assert(token == cast(unsigned char, token));
|
||||
return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
|
||||
luaO_pushfstring(ls->L, "char(%d)", token);
|
||||
}
|
||||
else {
|
||||
const char *s = luaX_tokens[token - FIRST_RESERVED];
|
||||
if (token < TK_EOS)
|
||||
if (token < TK_EOS) /* fixed format (symbols and reserved words)? */
|
||||
return luaO_pushfstring(ls->L, LUA_QS, s);
|
||||
else
|
||||
else /* names, strings, and numerals */
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,9 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
|||
setbvalue(o, 1); /* t[string] = true */
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
else { /* string already present */
|
||||
ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */
|
||||
}
|
||||
L->top--; /* remove string from stack */
|
||||
return ts;
|
||||
}
|
||||
|
@ -221,13 +224,24 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) {
|
|||
|
||||
|
||||
/* LUA_NUMBER */
|
||||
/*
|
||||
** this function is quite liberal in what it accepts, as 'luaO_str2d'
|
||||
** will reject ill-formed numerals.
|
||||
*/
|
||||
static void read_numeral (LexState *ls, SemInfo *seminfo) {
|
||||
const char *expo = "Ee";
|
||||
int first = ls->current;
|
||||
lua_assert(lisdigit(ls->current));
|
||||
do {
|
||||
save_and_next(ls);
|
||||
if (check_next(ls, "EePp")) /* exponent part? */
|
||||
save_and_next(ls);
|
||||
if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */
|
||||
expo = "Pp";
|
||||
for (;;) {
|
||||
if (check_next(ls, expo)) /* exponent part? */
|
||||
check_next(ls, "+-"); /* optional exponent sign */
|
||||
} while (lislalnum(ls->current) || ls->current == '.');
|
||||
if (lisxdigit(ls->current) || ls->current == '.')
|
||||
save_and_next(ls);
|
||||
else break;
|
||||
}
|
||||
save(ls, '\0');
|
||||
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
|
||||
if (!buff2d(ls->buff, &seminfo->r)) /* format error? */
|
||||
|
@ -301,7 +315,7 @@ static int readhexaesc (LexState *ls) {
|
|||
int c[3], i; /* keep input for error message */
|
||||
int r = 0; /* result accumulator */
|
||||
c[0] = 'x'; /* for error message */
|
||||
for (i = 1; i < 3; i++) { /* read two hexa digits */
|
||||
for (i = 1; i < 3; i++) { /* read two hexadecimal digits */
|
||||
c[i] = next(ls);
|
||||
if (!lisxdigit(c[i]))
|
||||
escerror(ls, c, i + 1, "hexadecimal digit expected");
|
||||
|
@ -479,8 +493,8 @@ static int llex (LexState *ls, SemInfo *seminfo) {
|
|||
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
|
||||
luaZ_bufflen(ls->buff));
|
||||
seminfo->ts = ts;
|
||||
if (ts->tsv.reserved > 0) /* reserved word? */
|
||||
return ts->tsv.reserved - 1 + FIRST_RESERVED;
|
||||
if (isreserved(ts)) /* reserved word? */
|
||||
return ts->tsv.extra - 1 + FIRST_RESERVED;
|
||||
else {
|
||||
return TK_NAME;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ typedef unsigned char lu_byte;
|
|||
|
||||
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
|
||||
|
||||
#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2))
|
||||
|
||||
|
||||
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
|
||||
|
||||
|
@ -197,7 +199,7 @@ typedef lu_int32 Instruction;
|
|||
** both small and large values (outside the range of integers).
|
||||
*/
|
||||
|
||||
#if defined(MS_ASMTRICK) /* { */
|
||||
#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */
|
||||
/* trick with Microsoft assembler for X86 */
|
||||
|
||||
#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
|
||||
|
@ -208,31 +210,36 @@ typedef lu_int32 Instruction;
|
|||
|
||||
#elif defined(LUA_IEEE754TRICK) /* }{ */
|
||||
/* the next trick should work on any machine using IEEE754 with
|
||||
a 32-bit integer type */
|
||||
a 32-bit int type */
|
||||
|
||||
union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
|
||||
|
||||
#if !defined(LUA_IEEEENDIAN) /* { */
|
||||
#define LUAI_EXTRAIEEE \
|
||||
static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
|
||||
#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33)
|
||||
#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33)
|
||||
#else
|
||||
#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN
|
||||
#define LUAI_EXTRAIEEE /* empty */
|
||||
#endif /* } */
|
||||
|
||||
#define lua_number2int32(i,n,t) \
|
||||
{ LUAI_EXTRAIEEE \
|
||||
volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
|
||||
(i) = (t)u.l_p[LUA_IEEEENDIAN]; }
|
||||
(i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
|
||||
|
||||
#define luai_hashnum(i,n) \
|
||||
{ volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \
|
||||
(i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */
|
||||
|
||||
#define lua_number2int(i,n) lua_number2int32(i, n, int)
|
||||
#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
|
||||
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
|
||||
|
||||
/* the trick can be expanded to lua_Integer when it is a 32-bit value */
|
||||
#if defined(LUA_IEEELL)
|
||||
#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
|
||||
#endif
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
|
@ -248,7 +255,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
|
|||
|
||||
#if !defined(lua_number2unsigned) /* { */
|
||||
/* the following definition assures proper modulo behavior */
|
||||
#if defined(LUA_NUMBER_DOUBLE)
|
||||
#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT)
|
||||
#include <math.h>
|
||||
#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
|
||||
#define lua_number2unsigned(i,n) \
|
||||
|
@ -274,7 +281,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
|
|||
#include <math.h>
|
||||
|
||||
#define luai_hashnum(i,n) { int e; \
|
||||
n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
|
||||
n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
|
||||
lua_number2int(i, n); i += e; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,104 +17,99 @@
|
|||
#include "lualib.h"
|
||||
|
||||
|
||||
#define RADIANS_PER_DEGREE ( boost::math::constants::pi<double>() / 180.0)
|
||||
|
||||
|
||||
/* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */
|
||||
#if !defined(l_tg)
|
||||
#define l_tg(x) (x)
|
||||
#endif
|
||||
#define RADIANS_PER_DEGREE ( boost::math::constants::pi<lua_Number>()/180.0 )
|
||||
|
||||
|
||||
|
||||
static int math_abs (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_sin (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(sin)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_sinh (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(sinh)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_cos (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(cos)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_cosh (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(cosh)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_tan (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(tan)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_tanh (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(tanh)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_asin (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(asin)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_acos (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(acos)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_atan (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(atan)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_atan2 (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(atan2)(luaL_checknumber(L, 1),
|
||||
lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1),
|
||||
luaL_checknumber(L, 2)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_ceil (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(ceil)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_floor (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(floor)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_fmod (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(fmod)(luaL_checknumber(L, 1),
|
||||
lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
|
||||
luaL_checknumber(L, 2)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_modf (lua_State *L) {
|
||||
lua_Number ip;
|
||||
lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip);
|
||||
lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip);
|
||||
lua_pushnumber(L, ip);
|
||||
lua_pushnumber(L, fp);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int math_sqrt (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(sqrt)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int math_pow (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(pow)(luaL_checknumber(L, 1),
|
||||
luaL_checknumber(L, 2)));
|
||||
lua_Number x = luaL_checknumber(L, 1);
|
||||
lua_Number y = luaL_checknumber(L, 2);
|
||||
lua_pushnumber(L, l_mathop(pow)(x, y));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -122,11 +117,11 @@ static int math_log (lua_State *L) {
|
|||
lua_Number x = luaL_checknumber(L, 1);
|
||||
lua_Number res;
|
||||
if (lua_isnoneornil(L, 2))
|
||||
res = l_tg(log)(x);
|
||||
res = l_mathop(log)(x);
|
||||
else {
|
||||
lua_Number base = luaL_checknumber(L, 2);
|
||||
if (base == 10.0) res = l_tg(log10)(x);
|
||||
else res = l_tg(log)(x)/l_tg(log)(base);
|
||||
if (base == (lua_Number)10.0) res = l_mathop(log10)(x);
|
||||
else res = l_mathop(log)(x)/l_mathop(log)(base);
|
||||
}
|
||||
lua_pushnumber(L, res);
|
||||
return 1;
|
||||
|
@ -134,13 +129,13 @@ static int math_log (lua_State *L) {
|
|||
|
||||
#if defined(LUA_COMPAT_LOG10)
|
||||
static int math_log10 (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(log10)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int math_exp (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(exp)(luaL_checknumber(L, 1)));
|
||||
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -156,14 +151,15 @@ static int math_rad (lua_State *L) {
|
|||
|
||||
static int math_frexp (lua_State *L) {
|
||||
int e;
|
||||
lua_pushnumber(L, l_tg(frexp)(luaL_checknumber(L, 1), &e));
|
||||
lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
|
||||
lua_pushinteger(L, e);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int math_ldexp (lua_State *L) {
|
||||
lua_pushnumber(L, l_tg(ldexp)(luaL_checknumber(L, 1),
|
||||
luaL_checkint(L, 2)));
|
||||
lua_Number x = luaL_checknumber(L, 1);
|
||||
int ep = luaL_checkint(L, 2);
|
||||
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -208,15 +204,15 @@ static int math_random (lua_State *L) {
|
|||
}
|
||||
case 1: { /* only upper limit */
|
||||
lua_Number u = luaL_checknumber(L, 1);
|
||||
luaL_argcheck(L, 1.0 <= u, 1, "interval is empty");
|
||||
lua_pushnumber(L, l_tg(floor)(r*u) + 1.0); /* int in [1, u] */
|
||||
luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
|
||||
lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */
|
||||
break;
|
||||
}
|
||||
case 2: { /* lower and upper limits */
|
||||
lua_Number l = luaL_checknumber(L, 1);
|
||||
lua_Number u = luaL_checknumber(L, 2);
|
||||
luaL_argcheck(L, l <= u, 2, "interval is empty");
|
||||
lua_pushnumber(L, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */
|
||||
lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */
|
||||
break;
|
||||
}
|
||||
default: return luaL_error(L, "wrong number of arguments");
|
||||
|
@ -272,7 +268,7 @@ static const luaL_Reg mathlib[] = {
|
|||
*/
|
||||
LUAMOD_API int luaopen_math (lua_State *L) {
|
||||
luaL_newlib(L, mathlib);
|
||||
lua_pushnumber(L, boost::math::constants::pi<double>());
|
||||
lua_pushnumber(L, boost::math::constants::pi<lua_Number>());
|
||||
lua_setfield(L, -2, "pi");
|
||||
lua_pushnumber(L, HUGE_VAL);
|
||||
lua_setfield(L, -2, "huge");
|
||||
|
|
|
@ -93,22 +93,6 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
|
|||
}
|
||||
lua_assert((nsize == 0) == (newblock == NULL));
|
||||
g->GCdebt = (g->GCdebt + nsize) - realosize;
|
||||
#if defined(TRACEMEM)
|
||||
{ /* auxiliary patch to monitor garbage collection.
|
||||
** To plot, gnuplot with following command:
|
||||
** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines
|
||||
*/
|
||||
static unsigned long total = 0; /* our "time" */
|
||||
static FILE *f = NULL; /* output file */
|
||||
total++; /* "time" always grows */
|
||||
if ((total % 200) == 0) {
|
||||
if (f == NULL) f = fopen(TRACEMEM, "w");
|
||||
fprintf(f, "%lu %u %d %d\n", total,
|
||||
gettotalbytes(g), g->GCdebt, g->gcstate * 10000);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return newblock;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,17 @@
|
|||
#include "lua.h"
|
||||
|
||||
|
||||
/*
|
||||
** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is
|
||||
** always constant.
|
||||
** The macro is somewhat complex to avoid warnings:
|
||||
** +1 avoids warnings of "comparison has constant result";
|
||||
** cast to 'void' avoids warnings of "value unused".
|
||||
*/
|
||||
#define luaM_reallocv(L,b,on,n,e) \
|
||||
((cast(size_t, (n)+1) > MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \
|
||||
(luaM_toobig(L), (void *)0) : \
|
||||
luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
|
||||
(cast(void, \
|
||||
(cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \
|
||||
luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
|
||||
|
||||
#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0)
|
||||
#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0)
|
||||
|
|
|
@ -91,9 +91,9 @@
|
|||
#define LUA_OFSEP "_"
|
||||
|
||||
|
||||
#define LIBPREFIX "LOADLIB: "
|
||||
/* table (in the registry) that keeps handles for all loaded C libraries */
|
||||
#define CLIBS "_CLIBS"
|
||||
|
||||
#define POF LUA_POF
|
||||
#define LIB_FAIL "open"
|
||||
|
||||
|
||||
|
@ -247,48 +247,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
static void **ll_register (lua_State *L, const char *path) {
|
||||
void **plib;
|
||||
lua_pushfstring(L, "%s%s", LIBPREFIX, path);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
|
||||
if (!lua_isnil(L, -1)) /* is there an entry? */
|
||||
plib = (void **)lua_touserdata(L, -1);
|
||||
else { /* no entry yet; create one */
|
||||
lua_pop(L, 1); /* remove result from gettable */
|
||||
plib = (void **)lua_newuserdata(L, sizeof(const void *));
|
||||
*plib = NULL;
|
||||
luaL_setmetatable(L, "_LOADLIB");
|
||||
lua_pushfstring(L, "%s%s", LIBPREFIX, path);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
static void *ll_checkclib (lua_State *L, const char *path) {
|
||||
void *plib;
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
||||
lua_getfield(L, -1, path);
|
||||
plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */
|
||||
lua_pop(L, 2); /* pop CLIBS table and 'plib' */
|
||||
return plib;
|
||||
}
|
||||
|
||||
|
||||
static void ll_addtoclib (lua_State *L, const char *path, void *plib) {
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS);
|
||||
lua_pushlightuserdata(L, plib);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -3, path); /* CLIBS[path] = plib */
|
||||
lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */
|
||||
lua_pop(L, 1); /* pop CLIBS table */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** __gc tag method: calls library's `ll_unloadlib' function with the lib
|
||||
** handle
|
||||
** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib
|
||||
** handles in list CLIBS
|
||||
*/
|
||||
static int gctm (lua_State *L) {
|
||||
void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
|
||||
if (*lib) ll_unloadlib(*lib);
|
||||
*lib = NULL; /* mark library as closed */
|
||||
int n = luaL_len(L, 1);
|
||||
for (; n >= 1; n--) { /* for each handle, in reverse order */
|
||||
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */
|
||||
ll_unloadlib(lua_touserdata(L, -1));
|
||||
lua_pop(L, 1); /* pop handle */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
|
||||
void **reg = ll_register(L, path);
|
||||
if (*reg == NULL) *reg = ll_load(L, path, *sym == '*');
|
||||
if (*reg == NULL) return ERRLIB; /* unable to load library */
|
||||
void *reg = ll_checkclib(L, path); /* check loaded C libraries */
|
||||
if (reg == NULL) { /* must load library? */
|
||||
reg = ll_load(L, path, *sym == '*');
|
||||
if (reg == NULL) return ERRLIB; /* unable to load library */
|
||||
ll_addtoclib(L, path, reg);
|
||||
}
|
||||
if (*sym == '*') { /* loading only library (no function)? */
|
||||
lua_pushboolean(L, 1); /* return 'true' */
|
||||
return 0; /* no errors */
|
||||
}
|
||||
else {
|
||||
lua_CFunction f = ll_sym(L, *reg, sym);
|
||||
lua_CFunction f = ll_sym(L, reg, sym);
|
||||
if (f == NULL)
|
||||
return ERRFUNC; /* unable to find function */
|
||||
lua_pushcfunction(L, f); /* else create new function */
|
||||
|
@ -417,12 +423,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) {
|
|||
if (mark) {
|
||||
int stat;
|
||||
funcname = lua_pushlstring(L, modname, mark - modname);
|
||||
funcname = lua_pushfstring(L, POF"%s", funcname);
|
||||
funcname = lua_pushfstring(L, LUA_POF"%s", funcname);
|
||||
stat = ll_loadfunc(L, filename, funcname);
|
||||
if (stat != ERRFUNC) return stat;
|
||||
modname = mark + 1; /* else go ahead and try old-style name */
|
||||
}
|
||||
funcname = lua_pushfstring(L, POF"%s", modname);
|
||||
funcname = lua_pushfstring(L, LUA_POF"%s", modname);
|
||||
return ll_loadfunc(L, filename, funcname);
|
||||
}
|
||||
|
||||
|
@ -475,9 +481,9 @@ static void findloader (lua_State *L, const char *name) {
|
|||
lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */
|
||||
if (!lua_istable(L, 3))
|
||||
luaL_error(L, LUA_QL("package.searchers") " must be a table");
|
||||
/* iterate over available seachers to find a loader */
|
||||
/* iterate over available searchers to find a loader */
|
||||
for (i = 1; ; i++) {
|
||||
lua_rawgeti(L, 3, i); /* get a seacher */
|
||||
lua_rawgeti(L, 3, i); /* get a searcher */
|
||||
if (lua_isnil(L, -1)) { /* no more searchers? */
|
||||
lua_pop(L, 1); /* remove nil */
|
||||
luaL_pushresult(&msg); /* create error message */
|
||||
|
@ -665,18 +671,10 @@ static const luaL_Reg ll_funcs[] = {
|
|||
};
|
||||
|
||||
|
||||
static const lua_CFunction searchers[] =
|
||||
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_package (lua_State *L) {
|
||||
static void createsearcherstable (lua_State *L) {
|
||||
static const lua_CFunction searchers[] =
|
||||
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
|
||||
int i;
|
||||
/* create new type _LOADLIB */
|
||||
luaL_newmetatable(L, "_LOADLIB");
|
||||
lua_pushcfunction(L, gctm);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
/* create `package' table */
|
||||
luaL_newlib(L, pk_funcs);
|
||||
/* create 'searchers' table */
|
||||
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
||||
/* fill it with pre-defined searchers */
|
||||
|
@ -685,6 +683,19 @@ LUAMOD_API int luaopen_package (lua_State *L) {
|
|||
lua_pushcclosure(L, searchers[i], 1);
|
||||
lua_rawseti(L, -2, i+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_package (lua_State *L) {
|
||||
/* create table CLIBS to keep track of loaded C libraries */
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS);
|
||||
lua_createtable(L, 0, 1); /* metatable for CLIBS */
|
||||
lua_pushcfunction(L, gctm);
|
||||
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */
|
||||
lua_setmetatable(L, -2);
|
||||
/* create `package' table */
|
||||
luaL_newlib(L, pk_funcs);
|
||||
createsearcherstable(L);
|
||||
#if defined(LUA_COMPAT_LOADERS)
|
||||
lua_pushvalue(L, -1); /* make a copy of 'searchers' table */
|
||||
lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */
|
||||
|
|
|
@ -103,7 +103,7 @@ static int isneg (const char **s) {
|
|||
|
||||
static lua_Number readhexa (const char **s, lua_Number r, int *count) {
|
||||
for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */
|
||||
r = (r * 16.0) + cast_num(luaO_hexavalue(cast_uchar(**s)));
|
||||
r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s)));
|
||||
(*count)++;
|
||||
}
|
||||
return r;
|
||||
|
@ -148,7 +148,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
|||
*endptr = cast(char *, s); /* valid up to here */
|
||||
ret:
|
||||
if (neg) r = -r;
|
||||
return ldexp(r, e);
|
||||
return l_mathop(ldexp)(r, e);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -170,8 +170,7 @@ int luaO_str2d (const char *s, size_t len, lua_Number *result) {
|
|||
|
||||
|
||||
static void pushstr (lua_State *L, const char *str, size_t l) {
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
|
||||
incr_top(L);
|
||||
setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,8 +180,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||
for (;;) {
|
||||
const char *e = strchr(fmt, '%');
|
||||
if (e == NULL) break;
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt));
|
||||
incr_top(L);
|
||||
luaD_checkstack(L, 2); /* fmt + item */
|
||||
pushstr(L, fmt, e - fmt);
|
||||
switch (*(e+1)) {
|
||||
case 's': {
|
||||
const char *s = va_arg(argp, char *);
|
||||
|
@ -197,13 +196,11 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||
break;
|
||||
}
|
||||
case 'd': {
|
||||
setnvalue(L->top, cast_num(va_arg(argp, int)));
|
||||
incr_top(L);
|
||||
setnvalue(L->top++, cast_num(va_arg(argp, int)));
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
|
||||
incr_top(L);
|
||||
setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
|
@ -225,6 +222,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
|||
n += 2;
|
||||
fmt = e+2;
|
||||
}
|
||||
luaD_checkstack(L, 1);
|
||||
pushstr(L, fmt, strlen(fmt));
|
||||
if (n > 0) luaV_concat(L, n + 1);
|
||||
return svalue(L->top - 1);
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
** bit 6: whether value is collectable
|
||||
*/
|
||||
|
||||
#define VARBITS (3 << 4)
|
||||
|
||||
|
||||
/*
|
||||
** LUA_TFUNCTION variants:
|
||||
** 0 - Lua function
|
||||
|
@ -48,6 +51,11 @@
|
|||
#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */
|
||||
|
||||
|
||||
/* Variant tags for strings */
|
||||
#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */
|
||||
#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
|
||||
|
||||
|
||||
/* Bit mark for collectable types */
|
||||
#define BIT_ISCOLLECTABLE (1 << 6)
|
||||
|
||||
|
@ -108,23 +116,28 @@ typedef struct lua_TValue TValue;
|
|||
/* raw type tag of a TValue */
|
||||
#define rttype(o) ((o)->tt_)
|
||||
|
||||
/* tag with no variants (bits 0-3) */
|
||||
#define novariant(x) ((x) & 0x0F)
|
||||
|
||||
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
|
||||
#define ttype(o) (rttype(o) & 0x3F)
|
||||
|
||||
|
||||
/* type tag of a TValue with no variants (bits 0-3) */
|
||||
#define ttypenv(o) (rttype(o) & 0x0F)
|
||||
#define ttypenv(o) (novariant(rttype(o)))
|
||||
|
||||
|
||||
/* Macros to test type */
|
||||
#define checktag(o,t) (rttype(o) == (t))
|
||||
#define checktype(o,t) (ttypenv(o) == (t))
|
||||
#define ttisnumber(o) checktag((o), LUA_TNUMBER)
|
||||
#define ttisnil(o) checktag((o), LUA_TNIL)
|
||||
#define ttisboolean(o) checktag((o), LUA_TBOOLEAN)
|
||||
#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA)
|
||||
#define ttisstring(o) checktag((o), ctb(LUA_TSTRING))
|
||||
#define ttisstring(o) checktype((o), LUA_TSTRING)
|
||||
#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR))
|
||||
#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR))
|
||||
#define ttistable(o) checktag((o), ctb(LUA_TTABLE))
|
||||
#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION)
|
||||
#define ttisfunction(o) checktype(o, LUA_TFUNCTION)
|
||||
#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION)
|
||||
#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL))
|
||||
#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL))
|
||||
|
@ -160,7 +173,7 @@ typedef struct lua_TValue TValue;
|
|||
|
||||
|
||||
/* Macros for internal tests */
|
||||
#define righttt(obj) (ttypenv(obj) == gcvalue(obj)->gch.tt)
|
||||
#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt)
|
||||
|
||||
#define checkliveness(g,obj) \
|
||||
lua_longassert(!iscollectable(obj) || \
|
||||
|
@ -173,8 +186,6 @@ typedef struct lua_TValue TValue;
|
|||
#define setnvalue(obj,x) \
|
||||
{ TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); }
|
||||
|
||||
#define changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(x))
|
||||
|
||||
#define setnilvalue(obj) settt_(obj, LUA_TNIL)
|
||||
|
||||
#define setfvalue(obj,x) \
|
||||
|
@ -192,7 +203,8 @@ typedef struct lua_TValue TValue;
|
|||
|
||||
#define setsvalue(L,obj,x) \
|
||||
{ TValue *io=(obj); \
|
||||
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TSTRING)); \
|
||||
TString *x_ = (x); \
|
||||
val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \
|
||||
checkliveness(G(L),io); }
|
||||
|
||||
#define setuvalue(L,obj,x) \
|
||||
|
@ -220,11 +232,6 @@ typedef struct lua_TValue TValue;
|
|||
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \
|
||||
checkliveness(G(L),io); }
|
||||
|
||||
#define setptvalue(L,obj,x) \
|
||||
{ TValue *io=(obj); \
|
||||
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \
|
||||
checkliveness(G(L),io); }
|
||||
|
||||
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
|
||||
|
||||
|
||||
|
@ -255,6 +262,8 @@ typedef struct lua_TValue TValue;
|
|||
#define setsvalue2n setsvalue
|
||||
|
||||
|
||||
/* check whether a number is valid (useful only for NaN trick) */
|
||||
#define luai_checknum(L,o,c) { /* empty */ }
|
||||
|
||||
|
||||
/*
|
||||
|
@ -262,10 +271,7 @@ typedef struct lua_TValue TValue;
|
|||
** NaN Trick
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
#if defined(LUA_NANTRICK) \
|
||||
|| defined(LUA_NANTRICK_LE) \
|
||||
|| defined(LUA_NANTRICK_BE)
|
||||
#if defined(LUA_NANTRICK)
|
||||
|
||||
/*
|
||||
** numbers are represented in the 'd_' field. All other values have the
|
||||
|
@ -273,15 +279,23 @@ typedef struct lua_TValue TValue;
|
|||
** a "signaled NaN", which is never generated by regular operations by
|
||||
** the CPU (nor by 'strtod')
|
||||
*/
|
||||
#if !defined(NNMARK)
|
||||
|
||||
/* allows for external implementation for part of the trick */
|
||||
#if !defined(NNMARK) /* { */
|
||||
|
||||
|
||||
#if !defined(LUA_IEEEENDIAN)
|
||||
#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN'
|
||||
#endif
|
||||
|
||||
|
||||
#define NNMARK 0x7FF7A500
|
||||
#define NNMASK 0x7FFFFF00
|
||||
#endif
|
||||
|
||||
#undef TValuefields
|
||||
#undef NILCONSTANT
|
||||
|
||||
#if defined(LUA_NANTRICK_LE)
|
||||
#if (LUA_IEEEENDIAN == 0) /* { */
|
||||
|
||||
/* little endian */
|
||||
#define TValuefields \
|
||||
|
@ -292,7 +306,7 @@ typedef struct lua_TValue TValue;
|
|||
#define d_(o) ((o)->u.d__)
|
||||
#define tt_(o) ((o)->u.i.tt__)
|
||||
|
||||
#elif defined(LUA_NANTRICK_BE)
|
||||
#else /* }{ */
|
||||
|
||||
/* big endian */
|
||||
#define TValuefields \
|
||||
|
@ -303,10 +317,9 @@ typedef struct lua_TValue TValue;
|
|||
#define d_(o) ((o)->u.d__)
|
||||
#define tt_(o) ((o)->u.i.tt__)
|
||||
|
||||
#elif !defined(TValuefields)
|
||||
#error option 'LUA_NANTRICK' needs declaration for 'TValuefields'
|
||||
#endif /* } */
|
||||
|
||||
#endif
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/* correspondence with standard representation */
|
||||
|
@ -347,21 +360,18 @@ typedef struct lua_TValue TValue;
|
|||
*/
|
||||
|
||||
#undef checktag
|
||||
#undef checktype
|
||||
#define checktag(o,t) (tt_(o) == tag2tt(t))
|
||||
#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS))
|
||||
|
||||
#undef ttisequal
|
||||
#define ttisequal(o1,o2) \
|
||||
(ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2)))
|
||||
|
||||
|
||||
|
||||
#undef luai_checknum
|
||||
#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; }
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define luai_checknum(L,o,c) { /* empty */ }
|
||||
|
||||
#endif
|
||||
/* }====================================================== */
|
||||
|
||||
|
@ -400,7 +410,7 @@ typedef union TString {
|
|||
L_Umaxalign dummy; /* ensures maximum alignment for strings */
|
||||
struct {
|
||||
CommonHeader;
|
||||
lu_byte reserved;
|
||||
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
|
||||
unsigned int hash;
|
||||
size_t len; /* number of characters in string */
|
||||
} tsv;
|
||||
|
@ -500,7 +510,7 @@ typedef struct UpVal {
|
|||
*/
|
||||
|
||||
#define ClosureHeader \
|
||||
CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist
|
||||
CommonHeader; lu_byte nupvalues; GCObject *gclist
|
||||
|
||||
typedef struct CClosure {
|
||||
ClosureHeader;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/*
|
||||
** Opcodes for Lua virtual machine
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
|
|
@ -25,11 +25,12 @@
|
|||
#if !defined(LUA_STRFTIMEOPTIONS)
|
||||
|
||||
#if !defined(LUA_USE_POSIX)
|
||||
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
|
||||
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
|
||||
#else
|
||||
#define LUA_STRFTIMEOPTIONS { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
|
||||
"E", "cCxXyY", \
|
||||
"O", "deHImMSuUVwWy" }
|
||||
#define LUA_STRFTIMEOPTIONS \
|
||||
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \
|
||||
"", "E", "cCxXyY", \
|
||||
"O", "deHImMSuUVwWy" }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -42,7 +43,7 @@
|
|||
*/
|
||||
#if defined(LUA_USE_MKSTEMP)
|
||||
#include <unistd.h>
|
||||
#define LUA_TMPNAMBUFSIZE 32
|
||||
#define LUA_TMPNAMBUFSIZE 32
|
||||
#define lua_tmpnam(b,e) { \
|
||||
strcpy(b, "/tmp/lua_XXXXXX"); \
|
||||
e = mkstemp(b); \
|
||||
|
@ -51,8 +52,8 @@
|
|||
|
||||
#elif !defined(lua_tmpnam)
|
||||
|
||||
#define LUA_TMPNAMBUFSIZE L_tmpnam
|
||||
#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
|
||||
#define LUA_TMPNAMBUFSIZE L_tmpnam
|
||||
#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); }
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -96,7 +97,7 @@ static int os_remove (lua_State *L) {
|
|||
static int os_rename (lua_State *L) {
|
||||
const char *fromname = luaL_checkstring(L, 1);
|
||||
const char *toname = luaL_checkstring(L, 2);
|
||||
return luaL_fileresult(L, rename(fromname, toname) == 0, fromname);
|
||||
return luaL_fileresult(L, rename(fromname, toname) == 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
|
|||
int i;
|
||||
Upvaldesc *up = fs->f->upvalues;
|
||||
for (i = 0; i < fs->nups; i++) {
|
||||
if (eqstr(up[i].name, name)) return i;
|
||||
if (luaS_eqstr(up[i].name, name)) return i;
|
||||
}
|
||||
return -1; /* not found */
|
||||
}
|
||||
|
@ -244,8 +244,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
|
|||
|
||||
static int searchvar (FuncState *fs, TString *n) {
|
||||
int i;
|
||||
for (i=fs->nactvar-1; i >= 0; i--) {
|
||||
if (eqstr(n, getlocvar(fs, i)->varname))
|
||||
for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
|
||||
if (luaS_eqstr(n, getlocvar(fs, i)->varname))
|
||||
return i;
|
||||
}
|
||||
return -1; /* not found */
|
||||
|
@ -341,7 +341,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) {
|
|||
FuncState *fs = ls->fs;
|
||||
Labellist *gl = &ls->dyd->gt;
|
||||
Labeldesc *gt = &gl->arr[g];
|
||||
lua_assert(eqstr(gt->name, label->name));
|
||||
lua_assert(luaS_eqstr(gt->name, label->name));
|
||||
if (gt->nactvar < label->nactvar) {
|
||||
TString *vname = getlocvar(fs, gt->nactvar)->varname;
|
||||
const char *msg = luaO_pushfstring(ls->L,
|
||||
|
@ -368,7 +368,7 @@ static int findlabel (LexState *ls, int g) {
|
|||
/* check labels in current block for a match */
|
||||
for (i = bl->firstlabel; i < dyd->label.n; i++) {
|
||||
Labeldesc *lb = &dyd->label.arr[i];
|
||||
if (eqstr(lb->name, gt->name)) { /* correct label? */
|
||||
if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */
|
||||
if (gt->nactvar > lb->nactvar &&
|
||||
(bl->upval || dyd->label.n > bl->firstlabel))
|
||||
luaK_patchclose(ls->fs, gt->pc, lb->nactvar);
|
||||
|
@ -402,7 +402,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) {
|
|||
Labellist *gl = &ls->dyd->gt;
|
||||
int i = ls->fs->bl->firstgoto;
|
||||
while (i < gl->n) {
|
||||
if (eqstr(gl->arr[i].name, lb->name))
|
||||
if (luaS_eqstr(gl->arr[i].name, lb->name))
|
||||
closegoto(ls, i, lb);
|
||||
else
|
||||
i++;
|
||||
|
@ -460,7 +460,7 @@ static void breaklabel (LexState *ls) {
|
|||
** message when label name is a reserved word (which can only be 'break')
|
||||
*/
|
||||
static l_noret undefgoto (LexState *ls, Labeldesc *gt) {
|
||||
const char *msg = (gt->name->tsv.reserved > 0)
|
||||
const char *msg = isreserved(gt->name)
|
||||
? "<%s> at line %d not inside a loop"
|
||||
: "no visible label " LUA_QS " for <goto> at line %d";
|
||||
msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line);
|
||||
|
@ -492,22 +492,34 @@ static void leaveblock (FuncState *fs) {
|
|||
|
||||
|
||||
/*
|
||||
** adds prototype being created into its parent list of prototypes
|
||||
** and codes instruction to create new closure
|
||||
** adds a new prototype into list of prototypes
|
||||
*/
|
||||
static void codeclosure (LexState *ls, Proto *clp, expdesc *v) {
|
||||
FuncState *fs = ls->fs->prev;
|
||||
Proto *f = fs->f; /* prototype of function creating new closure */
|
||||
static Proto *addprototype (LexState *ls) {
|
||||
Proto *clp;
|
||||
lua_State *L = ls->L;
|
||||
FuncState *fs = ls->fs;
|
||||
Proto *f = fs->f; /* prototype of current function */
|
||||
if (fs->np >= f->sizep) {
|
||||
int oldsize = f->sizep;
|
||||
luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *,
|
||||
MAXARG_Bx, "functions");
|
||||
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
|
||||
while (oldsize < f->sizep) f->p[oldsize++] = NULL;
|
||||
}
|
||||
f->p[fs->np++] = clp;
|
||||
luaC_objbarrier(ls->L, f, clp);
|
||||
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
|
||||
luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */
|
||||
f->p[fs->np++] = clp = luaF_newproto(L);
|
||||
luaC_objbarrier(L, f, clp);
|
||||
return clp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** codes instruction to create new closure in parent function.
|
||||
** The OP_CLOSURE instruction must use the last available register,
|
||||
** so that, if it invokes the GC, the GC knows which registers
|
||||
** are in use at that time.
|
||||
*/
|
||||
static void codeclosure (LexState *ls, expdesc *v) {
|
||||
FuncState *fs = ls->fs->prev;
|
||||
init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
|
||||
luaK_exp2nextreg(fs, v); /* fix it at the last register */
|
||||
}
|
||||
|
||||
|
||||
|
@ -528,13 +540,9 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
|||
fs->nactvar = 0;
|
||||
fs->firstlocal = ls->dyd->actvar.n;
|
||||
fs->bl = NULL;
|
||||
f = luaF_newproto(L);
|
||||
fs->f = f;
|
||||
f = fs->f;
|
||||
f->source = ls->source;
|
||||
f->maxstacksize = 2; /* registers 0/1 are always valid */
|
||||
/* anchor prototype (to avoid being collected) */
|
||||
setptvalue2s(L, L->top, f);
|
||||
incr_top(L);
|
||||
fs->h = luaH_new(L);
|
||||
/* anchor table of constants (to avoid being collected) */
|
||||
sethvalue2s(L, L->top, fs->h);
|
||||
|
@ -567,20 +575,6 @@ static void close_func (LexState *ls) {
|
|||
anchor_token(ls);
|
||||
L->top--; /* pop table of constants */
|
||||
luaC_checkGC(L);
|
||||
L->top--; /* pop prototype (after possible collection) */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** opens the main function, which is a regular vararg function with an
|
||||
** upvalue named LUA_ENV
|
||||
*/
|
||||
static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) {
|
||||
expdesc v;
|
||||
open_func(ls, fs, bl);
|
||||
fs->f->is_vararg = 1; /* main function is always vararg */
|
||||
init_exp(&v, VLOCAL, 0);
|
||||
newupvalue(fs, ls->envn, &v); /* create environment upvalue */
|
||||
}
|
||||
|
||||
|
||||
|
@ -794,8 +788,9 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
|||
/* body -> `(' parlist `)' block END */
|
||||
FuncState new_fs;
|
||||
BlockCnt bl;
|
||||
open_func(ls, &new_fs, &bl);
|
||||
new_fs.f = addprototype(ls);
|
||||
new_fs.f->linedefined = line;
|
||||
open_func(ls, &new_fs, &bl);
|
||||
checknext(ls, '(');
|
||||
if (ismethod) {
|
||||
new_localvarliteral(ls, "self"); /* create 'self' parameter */
|
||||
|
@ -806,7 +801,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) {
|
|||
statlist(ls);
|
||||
new_fs.f->lastlinedefined = ls->linenumber;
|
||||
check_match(ls, TK_END, TK_FUNCTION, line);
|
||||
codeclosure(ls, new_fs.f, e);
|
||||
codeclosure(ls, e);
|
||||
close_func(ls);
|
||||
}
|
||||
|
||||
|
@ -878,8 +873,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) {
|
|||
*/
|
||||
|
||||
|
||||
static void prefixexp (LexState *ls, expdesc *v) {
|
||||
/* prefixexp -> NAME | '(' expr ')' */
|
||||
static void primaryexp (LexState *ls, expdesc *v) {
|
||||
/* primaryexp -> NAME | '(' expr ')' */
|
||||
switch (ls->t.token) {
|
||||
case '(': {
|
||||
int line = ls->linenumber;
|
||||
|
@ -900,12 +895,12 @@ static void prefixexp (LexState *ls, expdesc *v) {
|
|||
}
|
||||
|
||||
|
||||
static void primaryexp (LexState *ls, expdesc *v) {
|
||||
/* primaryexp ->
|
||||
prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */
|
||||
static void suffixedexp (LexState *ls, expdesc *v) {
|
||||
/* suffixedexp ->
|
||||
primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */
|
||||
FuncState *fs = ls->fs;
|
||||
int line = ls->linenumber;
|
||||
prefixexp(ls, v);
|
||||
primaryexp(ls, v);
|
||||
for (;;) {
|
||||
switch (ls->t.token) {
|
||||
case '.': { /* fieldsel */
|
||||
|
@ -940,7 +935,7 @@ static void primaryexp (LexState *ls, expdesc *v) {
|
|||
|
||||
static void simpleexp (LexState *ls, expdesc *v) {
|
||||
/* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
|
||||
constructor | FUNCTION body | primaryexp */
|
||||
constructor | FUNCTION body | suffixedexp */
|
||||
switch (ls->t.token) {
|
||||
case TK_NUMBER: {
|
||||
init_exp(v, VKNUM, 0);
|
||||
|
@ -980,7 +975,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
|||
return;
|
||||
}
|
||||
default: {
|
||||
primaryexp(ls, v);
|
||||
suffixedexp(ls, v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1140,10 +1135,10 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
|
|||
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
|
||||
expdesc e;
|
||||
check_condition(ls, vkisvar(lh->v.k), "syntax error");
|
||||
if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
|
||||
if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */
|
||||
struct LHS_assign nv;
|
||||
nv.prev = lh;
|
||||
primaryexp(ls, &nv.v);
|
||||
suffixedexp(ls, &nv.v);
|
||||
if (nv.v.k != VINDEXED)
|
||||
check_conflict(ls, lh, &nv.v);
|
||||
checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
|
||||
|
@ -1199,7 +1194,7 @@ static void gotostat (LexState *ls, int pc) {
|
|||
static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
|
||||
int i;
|
||||
for (i = fs->bl->firstlabel; i < ll->n; i++) {
|
||||
if (eqstr(label, ll->arr[i].name)) {
|
||||
if (luaS_eqstr(label, ll->arr[i].name)) {
|
||||
const char *msg = luaO_pushfstring(fs->ls->L,
|
||||
"label " LUA_QS " already defined on line %d",
|
||||
getstr(label), ll->arr[i].line);
|
||||
|
@ -1209,6 +1204,13 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) {
|
|||
}
|
||||
|
||||
|
||||
/* skip no-op statements */
|
||||
static void skipnoopstat (LexState *ls) {
|
||||
while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
|
||||
statement(ls);
|
||||
}
|
||||
|
||||
|
||||
static void labelstat (LexState *ls, TString *label, int line) {
|
||||
/* label -> '::' NAME '::' */
|
||||
FuncState *fs = ls->fs;
|
||||
|
@ -1218,9 +1220,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
|
|||
checknext(ls, TK_DBCOLON); /* skip double colon */
|
||||
/* create new entry for this label */
|
||||
l = newlabelentry(ls, ll, label, line, fs->pc);
|
||||
/* skip other no-op statements */
|
||||
while (ls->t.token == ';' || ls->t.token == TK_DBCOLON)
|
||||
statement(ls);
|
||||
skipnoopstat(ls); /* skip other no-op statements */
|
||||
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
|
||||
/* assume that locals are already out of scope */
|
||||
ll->arr[l].nactvar = fs->bl->nactvar;
|
||||
|
@ -1383,6 +1383,7 @@ static void test_then_block (LexState *ls, int *escapelist) {
|
|||
luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */
|
||||
enterblock(fs, &bl, 0); /* must enter block before 'goto' */
|
||||
gotostat(ls, v.t); /* handle goto/break */
|
||||
skipnoopstat(ls); /* skip other no-op statements */
|
||||
if (block_follow(ls, 0)) { /* 'goto' is the entire block? */
|
||||
leaveblock(fs);
|
||||
return; /* and that is it */
|
||||
|
@ -1479,13 +1480,15 @@ static void exprstat (LexState *ls) {
|
|||
/* stat -> func | assignment */
|
||||
FuncState *fs = ls->fs;
|
||||
struct LHS_assign v;
|
||||
primaryexp(ls, &v.v);
|
||||
if (v.v.k == VCALL) /* stat -> func */
|
||||
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
|
||||
else { /* stat -> assignment */
|
||||
suffixedexp(ls, &v.v);
|
||||
if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */
|
||||
v.prev = NULL;
|
||||
assignment(ls, &v, 1);
|
||||
}
|
||||
else { /* stat -> func */
|
||||
check_condition(ls, v.v.k == VCALL, "syntax error");
|
||||
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1593,27 +1596,42 @@ static void statement (LexState *ls) {
|
|||
/* }====================================================================== */
|
||||
|
||||
|
||||
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
Dyndata *dyd, const char *name, int firstchar) {
|
||||
/*
|
||||
** compiles the main function, which is a regular vararg function with an
|
||||
** upvalue named LUA_ENV
|
||||
*/
|
||||
static void mainfunc (LexState *ls, FuncState *fs) {
|
||||
BlockCnt bl;
|
||||
expdesc v;
|
||||
open_func(ls, fs, &bl);
|
||||
fs->f->is_vararg = 1; /* main function is always vararg */
|
||||
init_exp(&v, VLOCAL, 0); /* create and... */
|
||||
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
|
||||
luaX_next(ls); /* read first token */
|
||||
statlist(ls); /* parse main body */
|
||||
check(ls, TK_EOS);
|
||||
close_func(ls);
|
||||
}
|
||||
|
||||
|
||||
Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
Dyndata *dyd, const char *name, int firstchar) {
|
||||
LexState lexstate;
|
||||
FuncState funcstate;
|
||||
BlockCnt bl;
|
||||
TString *tname = luaS_new(L, name);
|
||||
setsvalue2s(L, L->top, tname); /* push name to protect it */
|
||||
Closure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
||||
/* anchor closure (to avoid being collected) */
|
||||
setclLvalue(L, L->top, cl);
|
||||
incr_top(L);
|
||||
funcstate.f = cl->l.p = luaF_newproto(L);
|
||||
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
|
||||
lexstate.buff = buff;
|
||||
lexstate.dyd = dyd;
|
||||
dyd->actvar.n = dyd->gt.n = dyd->label.n = 0;
|
||||
luaX_setinput(L, &lexstate, z, tname, firstchar);
|
||||
open_mainfunc(&lexstate, &funcstate, &bl);
|
||||
luaX_next(&lexstate); /* read first token */
|
||||
statlist(&lexstate); /* main body */
|
||||
check(&lexstate, TK_EOS);
|
||||
close_func(&lexstate);
|
||||
L->top--; /* pop name */
|
||||
luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar);
|
||||
mainfunc(&lexstate, &funcstate);
|
||||
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
|
||||
/* all scopes should be correctly finished */
|
||||
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
|
||||
return funcstate.f;
|
||||
return cl; /* it's on the stack too */
|
||||
}
|
||||
|
||||
|
|
|
@ -111,8 +111,8 @@ typedef struct FuncState {
|
|||
} FuncState;
|
||||
|
||||
|
||||
LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
Dyndata *dyd, const char *name, int firstchar);
|
||||
LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
Dyndata *dyd, const char *name, int firstchar);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#define lstate_c
|
||||
#define LUA_CORE
|
||||
|
@ -37,7 +38,18 @@
|
|||
#endif
|
||||
|
||||
|
||||
#define MEMERRMSG "not enough memory"
|
||||
#define MEMERRMSG "not enough memory"
|
||||
|
||||
|
||||
/*
|
||||
** a macro to help the creation of a unique random seed when a state is
|
||||
** created; the seed is used to randomize hashes.
|
||||
*/
|
||||
#if !defined(luai_makeseed)
|
||||
#include <time.h>
|
||||
#define luai_makeseed() cast(unsigned int, time(NULL))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
@ -64,6 +76,28 @@ typedef struct LG {
|
|||
#define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l)))
|
||||
|
||||
|
||||
/*
|
||||
** Compute an initial seed as random as possible. In ANSI, rely on
|
||||
** Address Space Layout Randomization (if present) to increase
|
||||
** randomness..
|
||||
*/
|
||||
#define addbuff(b,p,e) \
|
||||
{ size_t t = cast(size_t, e); \
|
||||
memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
|
||||
|
||||
static unsigned int makeseed (lua_State *L) {
|
||||
char buff[4 * sizeof(size_t)];
|
||||
unsigned int h = luai_makeseed();
|
||||
int p = 0;
|
||||
addbuff(buff, p, L); /* heap variable */
|
||||
addbuff(buff, p, &h); /* local variable */
|
||||
addbuff(buff, p, luaO_nilobject); /* global variable */
|
||||
addbuff(buff, p, &lua_newstate); /* public function */
|
||||
lua_assert(p == sizeof(buff));
|
||||
return luaS_hash(buff, p, h);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
|
||||
** invariant
|
||||
|
@ -157,6 +191,8 @@ static void f_luaopen (lua_State *L, void *ud) {
|
|||
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
|
||||
luaS_fix(g->memerrmsg); /* it should never be collected */
|
||||
g->gcrunning = 1; /* allow gc */
|
||||
g->version = lua_version(NULL);
|
||||
luai_userstateopen(L);
|
||||
}
|
||||
|
||||
|
||||
|
@ -187,6 +223,8 @@ static void close_state (lua_State *L) {
|
|||
global_State *g = G(L);
|
||||
luaF_close(L, L->stack); /* close all upvalues for this thread */
|
||||
luaC_freeallobjects(L); /* collect all objects */
|
||||
if (g->version) /* closing a fully built state? */
|
||||
luai_userstateclose(L);
|
||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
|
||||
luaZ_freebuffer(L, &g->buff);
|
||||
freestack(L);
|
||||
|
@ -241,21 +279,23 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
g->frealloc = f;
|
||||
g->ud = ud;
|
||||
g->mainthread = L;
|
||||
g->seed = makeseed(L);
|
||||
g->uvhead.u.l.prev = &g->uvhead;
|
||||
g->uvhead.u.l.next = &g->uvhead;
|
||||
g->gcrunning = 0; /* no GC while building state */
|
||||
g->lastmajormem = 0;
|
||||
g->GCestimate = 0;
|
||||
g->strt.size = 0;
|
||||
g->strt.nuse = 0;
|
||||
g->strt.hash = NULL;
|
||||
setnilvalue(&g->l_registry);
|
||||
luaZ_initbuffer(L, &g->buff);
|
||||
g->panic = NULL;
|
||||
g->version = lua_version(NULL);
|
||||
g->version = NULL;
|
||||
g->gcstate = GCSpause;
|
||||
g->allgc = NULL;
|
||||
g->finobj = NULL;
|
||||
g->tobefnz = NULL;
|
||||
g->sweepgc = g->sweepfin = NULL;
|
||||
g->gray = g->grayagain = NULL;
|
||||
g->weak = g->ephemeron = g->allweak = NULL;
|
||||
g->totalbytes = sizeof(LG);
|
||||
|
@ -269,8 +309,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
close_state(L);
|
||||
L = NULL;
|
||||
}
|
||||
else
|
||||
luai_userstateopen(L);
|
||||
return L;
|
||||
}
|
||||
|
||||
|
@ -278,7 +316,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
LUA_API void lua_close (lua_State *L) {
|
||||
L = G(L)->mainthread; /* only the main thread can be closed */
|
||||
lua_lock(L);
|
||||
luai_userstateclose(L);
|
||||
close_state(L);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ typedef struct CallInfo {
|
|||
struct CallInfo *previous, *next; /* dynamic call link */
|
||||
short nresults; /* expected number of results from this function */
|
||||
lu_byte callstatus;
|
||||
ptrdiff_t extra;
|
||||
union {
|
||||
struct { /* only for Lua functions */
|
||||
StkId base; /* base for this function */
|
||||
|
@ -80,7 +81,6 @@ typedef struct CallInfo {
|
|||
int ctx; /* context info. in case of yields */
|
||||
lua_CFunction k; /* continuation in case of yields */
|
||||
ptrdiff_t old_errfunc;
|
||||
ptrdiff_t extra;
|
||||
lu_byte old_allowhook;
|
||||
lu_byte status;
|
||||
} c;
|
||||
|
@ -99,6 +99,7 @@ typedef struct CallInfo {
|
|||
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
|
||||
#define CIST_STAT (1<<5) /* call has an error status (pcall) */
|
||||
#define CIST_TAIL (1<<6) /* call was tail called */
|
||||
#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */
|
||||
|
||||
|
||||
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
|
||||
|
@ -112,9 +113,11 @@ typedef struct global_State {
|
|||
void *ud; /* auxiliary data to `frealloc' */
|
||||
lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
|
||||
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
|
||||
lu_mem lastmajormem; /* memory in use after last major collection */
|
||||
lu_mem GCmemtrav; /* memory traversed by the GC */
|
||||
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
|
||||
stringtable strt; /* hash table for strings */
|
||||
TValue l_registry;
|
||||
unsigned int seed; /* randomized seed for hashes */
|
||||
lu_byte currentwhite;
|
||||
lu_byte gcstate; /* state of garbage collector */
|
||||
lu_byte gckind; /* kind of GC running */
|
||||
|
@ -122,7 +125,8 @@ typedef struct global_State {
|
|||
int sweepstrgc; /* position of sweep in `strt' */
|
||||
GCObject *allgc; /* list of all collectable objects */
|
||||
GCObject *finobj; /* list of collectable objects with finalizers */
|
||||
GCObject **sweepgc; /* current position of sweep */
|
||||
GCObject **sweepgc; /* current position of sweep in list 'allgc' */
|
||||
GCObject **sweepfin; /* current position of sweep in list 'finobj' */
|
||||
GCObject *gray; /* list of gray objects */
|
||||
GCObject *grayagain; /* list of objects to be traversed atomically */
|
||||
GCObject *weak; /* list of tables with weak values */
|
||||
|
@ -132,7 +136,7 @@ typedef struct global_State {
|
|||
UpVal uvhead; /* head of double-linked list of all open upvalues */
|
||||
Mbuffer buff; /* temporary buffer for string concatenation */
|
||||
int gcpause; /* size of pause between successive GCs */
|
||||
int gcmajorinc; /* how much to wait for a major GC (only in gen. mode) */
|
||||
int gcmajorinc; /* pause between major collections (only in gen. mode) */
|
||||
int gcstepmul; /* GC `granularity' */
|
||||
lua_CFunction panic; /* to be called in unprotected errors */
|
||||
struct lua_State *mainthread;
|
||||
|
@ -192,11 +196,15 @@ union GCObject {
|
|||
#define gch(o) (&(o)->gch)
|
||||
|
||||
/* macros to convert a GCObject into a specific value */
|
||||
#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
|
||||
#define rawgco2ts(o) \
|
||||
check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts))
|
||||
#define gco2ts(o) (&rawgco2ts(o)->tsv)
|
||||
#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
|
||||
#define gco2u(o) (&rawgco2u(o)->uv)
|
||||
#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
|
||||
#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l))
|
||||
#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c))
|
||||
#define gco2cl(o) \
|
||||
check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))
|
||||
#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
|
||||
#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
|
||||
#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
|
||||
|
|
|
@ -17,7 +17,49 @@
|
|||
#include "lstring.h"
|
||||
|
||||
|
||||
/*
|
||||
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
|
||||
** compute its hash
|
||||
*/
|
||||
#if !defined(LUAI_HASHLIMIT)
|
||||
#define LUAI_HASHLIMIT 5
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** equality for long strings
|
||||
*/
|
||||
int luaS_eqlngstr (TString *a, TString *b) {
|
||||
size_t len = a->tsv.len;
|
||||
lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR);
|
||||
return (a == b) || /* same instance or... */
|
||||
((len == b->tsv.len) && /* equal length and ... */
|
||||
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** equality for strings
|
||||
*/
|
||||
int luaS_eqstr (TString *a, TString *b) {
|
||||
return (a->tsv.tt == b->tsv.tt) &&
|
||||
(a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b));
|
||||
}
|
||||
|
||||
|
||||
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
|
||||
unsigned int h = seed ^ cast(unsigned int, l);
|
||||
size_t l1;
|
||||
size_t step = (l >> LUAI_HASHLIMIT) + 1;
|
||||
for (l1 = l; l1 >= step; l1 -= step)
|
||||
h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** resizes the string table
|
||||
*/
|
||||
void luaS_resize (lua_State *L, int newsize) {
|
||||
int i;
|
||||
stringtable *tb = &G(L)->strt;
|
||||
|
@ -49,52 +91,81 @@ void luaS_resize (lua_State *L, int newsize) {
|
|||
}
|
||||
|
||||
|
||||
static TString *newlstr (lua_State *L, const char *str, size_t l,
|
||||
unsigned int h) {
|
||||
size_t totalsize; /* total size of TString object */
|
||||
GCObject **list; /* (pointer to) list where it will be inserted */
|
||||
/*
|
||||
** creates a new string object
|
||||
*/
|
||||
static TString *createstrobj (lua_State *L, const char *str, size_t l,
|
||||
int tag, unsigned int h, GCObject **list) {
|
||||
TString *ts;
|
||||
stringtable *tb = &G(L)->strt;
|
||||
if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
|
||||
luaM_toobig(L);
|
||||
if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
|
||||
luaS_resize(L, tb->size*2); /* too crowded */
|
||||
size_t totalsize; /* total size of TString object */
|
||||
totalsize = sizeof(TString) + ((l + 1) * sizeof(char));
|
||||
list = &tb->hash[lmod(h, tb->size)];
|
||||
ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts;
|
||||
ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts;
|
||||
ts->tsv.len = l;
|
||||
ts->tsv.hash = h;
|
||||
ts->tsv.reserved = 0;
|
||||
ts->tsv.extra = 0;
|
||||
memcpy(ts+1, str, l*sizeof(char));
|
||||
((char *)(ts+1))[l] = '\0'; /* ending 0 */
|
||||
tb->nuse++;
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
||||
/*
|
||||
** creates a new short string, inserting it into string table
|
||||
*/
|
||||
static TString *newshrstr (lua_State *L, const char *str, size_t l,
|
||||
unsigned int h) {
|
||||
GCObject **list; /* (pointer to) list where it will be inserted */
|
||||
stringtable *tb = &G(L)->strt;
|
||||
TString *s;
|
||||
if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
|
||||
luaS_resize(L, tb->size*2); /* too crowded */
|
||||
list = &tb->hash[lmod(h, tb->size)];
|
||||
s = createstrobj(L, str, l, LUA_TSHRSTR, h, list);
|
||||
tb->nuse++;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** checks whether short string exists and reuses it or creates a new one
|
||||
*/
|
||||
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
|
||||
GCObject *o;
|
||||
unsigned int h = cast(unsigned int, l); /* seed */
|
||||
size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
|
||||
size_t l1;
|
||||
for (l1=l; l1>=step; l1-=step) /* compute hash */
|
||||
h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
|
||||
for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
|
||||
global_State *g = G(L);
|
||||
unsigned int h = luaS_hash(str, l, g->seed);
|
||||
for (o = g->strt.hash[lmod(h, g->strt.size)];
|
||||
o != NULL;
|
||||
o = gch(o)->next) {
|
||||
TString *ts = rawgco2ts(o);
|
||||
if (h == ts->tsv.hash &&
|
||||
ts->tsv.len == l &&
|
||||
l == ts->tsv.len &&
|
||||
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
|
||||
if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */
|
||||
changewhite(o); /* resurrect it */
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
return newlstr(L, str, l, h); /* not found; create a new string */
|
||||
return newshrstr(L, str, l, h); /* not found; create a new string */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** new string (with explicit length)
|
||||
*/
|
||||
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
||||
if (l <= LUAI_MAXSHORTLEN) /* short string? */
|
||||
return internshrstr(L, str, l);
|
||||
else {
|
||||
if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
|
||||
luaM_toobig(L);
|
||||
return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** new zero-terminated string
|
||||
*/
|
||||
TString *luaS_new (lua_State *L, const char *str) {
|
||||
return luaS_newlstr(L, str, strlen(str));
|
||||
}
|
||||
|
|
|
@ -22,11 +22,20 @@
|
|||
|
||||
|
||||
/*
|
||||
** as all string are internalized, string equality becomes
|
||||
** pointer equality
|
||||
** test whether a string is a reserved word
|
||||
*/
|
||||
#define eqstr(a,b) ((a) == (b))
|
||||
#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0)
|
||||
|
||||
|
||||
/*
|
||||
** equality for short strings, which are always internalized
|
||||
*/
|
||||
#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b))
|
||||
|
||||
|
||||
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
|
||||
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
|
||||
LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
|
||||
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
|
||||
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
|
||||
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
|
||||
/* macro to `unsign' a character */
|
||||
#define uchar(c) ((unsigned char)(c))
|
||||
#define uchar(c) ((unsigned char)(c))
|
||||
|
||||
|
||||
|
||||
|
@ -118,7 +118,9 @@ static int str_rep (lua_State *L) {
|
|||
char *p = luaL_buffinitsize(L, &b, totallen);
|
||||
while (n-- > 1) { /* first n-1 copies (followed by separator) */
|
||||
memcpy(p, s, l * sizeof(char)); p += l;
|
||||
memcpy(p, sep, lsep * sizeof(char)); p += lsep;
|
||||
if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */
|
||||
memcpy(p, sep, lsep * sizeof(char)); p += lsep;
|
||||
}
|
||||
}
|
||||
memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */
|
||||
luaL_pushresultsize(&b, totallen);
|
||||
|
@ -191,7 +193,9 @@ static int str_dump (lua_State *L) {
|
|||
#define CAP_UNFINISHED (-1)
|
||||
#define CAP_POSITION (-2)
|
||||
|
||||
|
||||
typedef struct MatchState {
|
||||
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
|
||||
const char *src_init; /* init of source string */
|
||||
const char *src_end; /* end ('\0') of source string */
|
||||
const char *p_end; /* end ('\0') of pattern */
|
||||
|
@ -204,6 +208,16 @@ typedef struct MatchState {
|
|||
} MatchState;
|
||||
|
||||
|
||||
/* recursive function */
|
||||
static const char *match (MatchState *ms, const char *s, const char *p);
|
||||
|
||||
|
||||
/* maximum recursion depth for 'match' */
|
||||
#if !defined(MAXCCALLS)
|
||||
#define MAXCCALLS 200
|
||||
#endif
|
||||
|
||||
|
||||
#define L_ESC '%'
|
||||
#define SPECIALS "^$*+?.([%-"
|
||||
|
||||
|
@ -291,19 +305,22 @@ static int matchbracketclass (int c, const char *p, const char *ec) {
|
|||
}
|
||||
|
||||
|
||||
static int singlematch (int c, const char *p, const char *ep) {
|
||||
switch (*p) {
|
||||
case '.': return 1; /* matches any char */
|
||||
case L_ESC: return match_class(c, uchar(*(p+1)));
|
||||
case '[': return matchbracketclass(c, p, ep-1);
|
||||
default: return (uchar(*p) == c);
|
||||
static int singlematch (MatchState *ms, const char *s, const char *p,
|
||||
const char *ep) {
|
||||
if (s >= ms->src_end)
|
||||
return 0;
|
||||
else {
|
||||
int c = uchar(*s);
|
||||
switch (*p) {
|
||||
case '.': return 1; /* matches any char */
|
||||
case L_ESC: return match_class(c, uchar(*(p+1)));
|
||||
case '[': return matchbracketclass(c, p, ep-1);
|
||||
default: return (uchar(*p) == c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *match (MatchState *ms, const char *s, const char *p);
|
||||
|
||||
|
||||
static const char *matchbalance (MatchState *ms, const char *s,
|
||||
const char *p) {
|
||||
if (p >= ms->p_end - 1)
|
||||
|
@ -328,7 +345,7 @@ static const char *matchbalance (MatchState *ms, const char *s,
|
|||
static const char *max_expand (MatchState *ms, const char *s,
|
||||
const char *p, const char *ep) {
|
||||
ptrdiff_t i = 0; /* counts maximum expand for item */
|
||||
while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
|
||||
while (singlematch(ms, s + i, p, ep))
|
||||
i++;
|
||||
/* keeps trying to match with the maximum repetitions */
|
||||
while (i>=0) {
|
||||
|
@ -346,7 +363,7 @@ static const char *min_expand (MatchState *ms, const char *s,
|
|||
const char *res = match(ms, s, ep+1);
|
||||
if (res != NULL)
|
||||
return res;
|
||||
else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
|
||||
else if (singlematch(ms, s, p, ep))
|
||||
s++; /* try with one more repetition */
|
||||
else return NULL;
|
||||
}
|
||||
|
@ -390,79 +407,105 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
|
|||
|
||||
|
||||
static const char *match (MatchState *ms, const char *s, const char *p) {
|
||||
if (ms->matchdepth-- == 0)
|
||||
luaL_error(ms->L, "pattern too complex");
|
||||
init: /* using goto's to optimize tail recursion */
|
||||
if (p == ms->p_end) /* end of pattern? */
|
||||
return s; /* match succeeded */
|
||||
switch (*p) {
|
||||
case '(': { /* start capture */
|
||||
if (*(p+1) == ')') /* position capture? */
|
||||
return start_capture(ms, s, p+2, CAP_POSITION);
|
||||
else
|
||||
return start_capture(ms, s, p+1, CAP_UNFINISHED);
|
||||
}
|
||||
case ')': { /* end capture */
|
||||
return end_capture(ms, s, p+1);
|
||||
}
|
||||
case '$': {
|
||||
if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */
|
||||
return (s == ms->src_end) ? s : NULL; /* check end of string */
|
||||
else goto dflt;
|
||||
}
|
||||
case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
|
||||
switch (*(p+1)) {
|
||||
case 'b': { /* balanced string? */
|
||||
s = matchbalance(ms, s, p+2);
|
||||
if (s == NULL) return NULL;
|
||||
p+=4; goto init; /* else return match(ms, s, p+4); */
|
||||
}
|
||||
case 'f': { /* frontier? */
|
||||
const char *ep; char previous;
|
||||
p += 2;
|
||||
if (*p != '[')
|
||||
luaL_error(ms->L, "missing " LUA_QL("[") " after "
|
||||
LUA_QL("%%f") " in pattern");
|
||||
ep = classend(ms, p); /* points to what is next */
|
||||
previous = (s == ms->src_init) ? '\0' : *(s-1);
|
||||
if (matchbracketclass(uchar(previous), p, ep-1) ||
|
||||
!matchbracketclass(uchar(*s), p, ep-1)) return NULL;
|
||||
p=ep; goto init; /* else return match(ms, s, ep); */
|
||||
}
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
case '8': case '9': { /* capture results (%0-%9)? */
|
||||
s = match_capture(ms, s, uchar(*(p+1)));
|
||||
if (s == NULL) return NULL;
|
||||
p+=2; goto init; /* else return match(ms, s, p+2) */
|
||||
}
|
||||
default: goto dflt;
|
||||
if (p != ms->p_end) { /* end of pattern? */
|
||||
switch (*p) {
|
||||
case '(': { /* start capture */
|
||||
if (*(p + 1) == ')') /* position capture? */
|
||||
s = start_capture(ms, s, p + 2, CAP_POSITION);
|
||||
else
|
||||
s = start_capture(ms, s, p + 1, CAP_UNFINISHED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: dflt: { /* pattern class plus optional suffix */
|
||||
const char *ep = classend(ms, p); /* points to what is next */
|
||||
int m = s < ms->src_end && singlematch(uchar(*s), p, ep);
|
||||
switch (*ep) {
|
||||
case '?': { /* optional */
|
||||
const char *res;
|
||||
if (m && ((res=match(ms, s+1, ep+1)) != NULL))
|
||||
return res;
|
||||
p=ep+1; goto init; /* else return match(ms, s, ep+1); */
|
||||
case ')': { /* end capture */
|
||||
s = end_capture(ms, s, p + 1);
|
||||
break;
|
||||
}
|
||||
case '$': {
|
||||
if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */
|
||||
goto dflt; /* no; go to default */
|
||||
s = (s == ms->src_end) ? s : NULL; /* check end of string */
|
||||
break;
|
||||
}
|
||||
case L_ESC: { /* escaped sequences not in the format class[*+?-]? */
|
||||
switch (*(p + 1)) {
|
||||
case 'b': { /* balanced string? */
|
||||
s = matchbalance(ms, s, p + 2);
|
||||
if (s != NULL) {
|
||||
p += 4; goto init; /* return match(ms, s, p + 4); */
|
||||
} /* else fail (s == NULL) */
|
||||
break;
|
||||
}
|
||||
case 'f': { /* frontier? */
|
||||
const char *ep; char previous;
|
||||
p += 2;
|
||||
if (*p != '[')
|
||||
luaL_error(ms->L, "missing " LUA_QL("[") " after "
|
||||
LUA_QL("%%f") " in pattern");
|
||||
ep = classend(ms, p); /* points to what is next */
|
||||
previous = (s == ms->src_init) ? '\0' : *(s - 1);
|
||||
if (!matchbracketclass(uchar(previous), p, ep - 1) &&
|
||||
matchbracketclass(uchar(*s), p, ep - 1)) {
|
||||
p = ep; goto init; /* return match(ms, s, ep); */
|
||||
}
|
||||
s = NULL; /* match failed */
|
||||
break;
|
||||
}
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
case '8': case '9': { /* capture results (%0-%9)? */
|
||||
s = match_capture(ms, s, uchar(*(p + 1)));
|
||||
if (s != NULL) {
|
||||
p += 2; goto init; /* return match(ms, s, p + 2) */
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: goto dflt;
|
||||
}
|
||||
case '*': { /* 0 or more repetitions */
|
||||
return max_expand(ms, s, p, ep);
|
||||
break;
|
||||
}
|
||||
default: dflt: { /* pattern class plus optional suffix */
|
||||
const char *ep = classend(ms, p); /* points to optional suffix */
|
||||
/* does not match at least once? */
|
||||
if (!singlematch(ms, s, p, ep)) {
|
||||
if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */
|
||||
p = ep + 1; goto init; /* return match(ms, s, ep + 1); */
|
||||
}
|
||||
else /* '+' or no suffix */
|
||||
s = NULL; /* fail */
|
||||
}
|
||||
case '+': { /* 1 or more repetitions */
|
||||
return (m ? max_expand(ms, s+1, p, ep) : NULL);
|
||||
}
|
||||
case '-': { /* 0 or more repetitions (minimum) */
|
||||
return min_expand(ms, s, p, ep);
|
||||
}
|
||||
default: {
|
||||
if (!m) return NULL;
|
||||
s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
|
||||
else { /* matched once */
|
||||
switch (*ep) { /* handle optional suffix */
|
||||
case '?': { /* optional */
|
||||
const char *res;
|
||||
if ((res = match(ms, s + 1, ep + 1)) != NULL)
|
||||
s = res;
|
||||
else {
|
||||
p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '+': /* 1 or more repetitions */
|
||||
s++; /* 1 match already done */
|
||||
/* go through */
|
||||
case '*': /* 0 or more repetitions */
|
||||
s = max_expand(ms, s, p, ep);
|
||||
break;
|
||||
case '-': /* 0 or more repetitions (minimum) */
|
||||
s = min_expand(ms, s, p, ep);
|
||||
break;
|
||||
default: /* no suffix */
|
||||
s++; p = ep; goto init; /* return match(ms, s + 1, ep); */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ms->matchdepth++;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
@ -558,12 +601,14 @@ static int str_find_aux (lua_State *L, int find) {
|
|||
p++; lp--; /* skip anchor character */
|
||||
}
|
||||
ms.L = L;
|
||||
ms.matchdepth = MAXCCALLS;
|
||||
ms.src_init = s;
|
||||
ms.src_end = s + ls;
|
||||
ms.p_end = p + lp;
|
||||
do {
|
||||
const char *res;
|
||||
ms.level = 0;
|
||||
lua_assert(ms.matchdepth == MAXCCALLS);
|
||||
if ((res=match(&ms, s1, p)) != NULL) {
|
||||
if (find) {
|
||||
lua_pushinteger(L, s1 - s + 1); /* start */
|
||||
|
@ -597,6 +642,7 @@ static int gmatch_aux (lua_State *L) {
|
|||
const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
|
||||
const char *src;
|
||||
ms.L = L;
|
||||
ms.matchdepth = MAXCCALLS;
|
||||
ms.src_init = s;
|
||||
ms.src_end = s+ls;
|
||||
ms.p_end = p + lp;
|
||||
|
@ -605,6 +651,7 @@ static int gmatch_aux (lua_State *L) {
|
|||
src++) {
|
||||
const char *e;
|
||||
ms.level = 0;
|
||||
lua_assert(ms.matchdepth == MAXCCALLS);
|
||||
if ((e = match(&ms, src, p)) != NULL) {
|
||||
lua_Integer newstart = e-s;
|
||||
if (e == src) newstart++; /* empty match? go at least one position */
|
||||
|
@ -702,12 +749,14 @@ static int str_gsub (lua_State *L) {
|
|||
p++; lp--; /* skip anchor character */
|
||||
}
|
||||
ms.L = L;
|
||||
ms.matchdepth = MAXCCALLS;
|
||||
ms.src_init = src;
|
||||
ms.src_end = src+srcl;
|
||||
ms.p_end = p + lp;
|
||||
while (n < max_s) {
|
||||
const char *e;
|
||||
ms.level = 0;
|
||||
lua_assert(ms.matchdepth == MAXCCALLS);
|
||||
e = match(&ms, src, p);
|
||||
if (e) {
|
||||
n++;
|
||||
|
@ -744,20 +793,17 @@ static int str_gsub (lua_State *L) {
|
|||
#if !defined(LUA_INTFRMLEN) /* { */
|
||||
#if defined(LUA_USE_LONGLONG)
|
||||
|
||||
#define LUA_INTFRMLEN "ll"
|
||||
#define LUA_INTFRM_T long long
|
||||
#define LUA_INTFRMLEN "ll"
|
||||
#define LUA_INTFRM_T long long
|
||||
|
||||
#else
|
||||
|
||||
#define LUA_INTFRMLEN "l"
|
||||
#define LUA_INTFRM_T long
|
||||
#define LUA_INTFRMLEN "l"
|
||||
#define LUA_INTFRM_T long
|
||||
|
||||
#endif
|
||||
#endif /* } */
|
||||
|
||||
#define MAX_UINTFRM ((lua_Number)(~(unsigned LUA_INTFRM_T)0))
|
||||
#define MAX_INTFRM ((lua_Number)((~(unsigned LUA_INTFRM_T)0)/2))
|
||||
#define MIN_INTFRM (-(lua_Number)((~(unsigned LUA_INTFRM_T)0)/2) - 1)
|
||||
|
||||
/*
|
||||
** LUA_FLTFRMLEN is the length modifier for float conversions in
|
||||
|
@ -766,8 +812,8 @@ static int str_gsub (lua_State *L) {
|
|||
*/
|
||||
#if !defined(LUA_FLTFRMLEN)
|
||||
|
||||
#define LUA_FLTFRMLEN ""
|
||||
#define LUA_FLTFRM_T double
|
||||
#define LUA_FLTFRMLEN ""
|
||||
#define LUA_FLTFRM_T double
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -867,23 +913,27 @@ static int str_format (lua_State *L) {
|
|||
nb = sprintf(buff, form, luaL_checkint(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'd': case 'i': {
|
||||
case 'd': case 'i': {
|
||||
lua_Number n = luaL_checknumber(L, arg);
|
||||
luaL_argcheck(L, (MIN_INTFRM - 1) < n && n < (MAX_INTFRM + 1), arg,
|
||||
LUA_INTFRM_T ni = (LUA_INTFRM_T)n;
|
||||
lua_Number diff = n - (lua_Number)ni;
|
||||
luaL_argcheck(L, -1 < diff && diff < 1, arg,
|
||||
"not a number in proper range");
|
||||
addlenmod(form, LUA_INTFRMLEN);
|
||||
nb = sprintf(buff, form, (LUA_INTFRM_T)n);
|
||||
nb = sprintf(buff, form, ni);
|
||||
break;
|
||||
}
|
||||
case 'o': case 'u': case 'x': case 'X': {
|
||||
case 'o': case 'u': case 'x': case 'X': {
|
||||
lua_Number n = luaL_checknumber(L, arg);
|
||||
luaL_argcheck(L, 0 <= n && n < (MAX_UINTFRM + 1), arg,
|
||||
unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n;
|
||||
lua_Number diff = n - (lua_Number)ni;
|
||||
luaL_argcheck(L, -1 < diff && diff < 1, arg,
|
||||
"not a non-negative number in proper range");
|
||||
addlenmod(form, LUA_INTFRMLEN);
|
||||
nb = sprintf(buff, form, (unsigned LUA_INTFRM_T)n);
|
||||
nb = sprintf(buff, form, ni);
|
||||
break;
|
||||
}
|
||||
case 'e': case 'E': case 'f':
|
||||
case 'e': case 'E': case 'f':
|
||||
#if defined(LUA_USE_AFORMAT)
|
||||
case 'a': case 'A':
|
||||
#endif
|
||||
|
|
|
@ -47,10 +47,10 @@
|
|||
#define MAXASIZE (1 << MAXBITS)
|
||||
|
||||
|
||||
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
|
||||
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
|
||||
|
||||
#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
|
||||
#define hashboolean(t,p) hashpow2(t, p)
|
||||
#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
|
||||
#define hashboolean(t,p) hashpow2(t, p)
|
||||
|
||||
|
||||
/*
|
||||
|
@ -97,7 +97,15 @@ static Node *mainposition (const Table *t, const TValue *key) {
|
|||
switch (ttype(key)) {
|
||||
case LUA_TNUMBER:
|
||||
return hashnum(t, nvalue(key));
|
||||
case LUA_TSTRING:
|
||||
case LUA_TLNGSTR: {
|
||||
TString *s = rawtsvalue(key);
|
||||
if (s->tsv.extra == 0) { /* no hash? */
|
||||
s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash);
|
||||
s->tsv.extra = 1; /* now it has its hash */
|
||||
}
|
||||
return hashstr(t, rawtsvalue(key));
|
||||
}
|
||||
case LUA_TSHRSTR:
|
||||
return hashstr(t, rawtsvalue(key));
|
||||
case LUA_TBOOLEAN:
|
||||
return hashboolean(t, bvalue(key));
|
||||
|
@ -452,12 +460,13 @@ const TValue *luaH_getint (Table *t, int key) {
|
|||
|
||||
|
||||
/*
|
||||
** search function for strings
|
||||
** search function for short strings
|
||||
*/
|
||||
const TValue *luaH_getstr (Table *t, TString *key) {
|
||||
Node *n = hashstr(t, key);
|
||||
lua_assert(key->tsv.tt == LUA_TSHRSTR);
|
||||
do { /* check whether `key' is somewhere in the chain */
|
||||
if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key))
|
||||
if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key))
|
||||
return gval(n); /* that's it */
|
||||
else n = gnext(n);
|
||||
} while (n);
|
||||
|
@ -469,14 +478,14 @@ const TValue *luaH_getstr (Table *t, TString *key) {
|
|||
** main search function
|
||||
*/
|
||||
const TValue *luaH_get (Table *t, const TValue *key) {
|
||||
switch (ttypenv(key)) {
|
||||
switch (ttype(key)) {
|
||||
case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key));
|
||||
case LUA_TNIL: return luaO_nilobject;
|
||||
case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
|
||||
case LUA_TNUMBER: {
|
||||
int k;
|
||||
lua_Number n = nvalue(key);
|
||||
lua_number2int(k, n);
|
||||
if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
|
||||
if (luai_numeq(cast_num(k), n)) /* index is int? */
|
||||
return luaH_getint(t, k); /* use specialized version */
|
||||
/* else go through */
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
#define invalidateTMcache(t) ((t)->flags = 0)
|
||||
|
||||
/* returns the key, given the value of a table entry */
|
||||
#define keyfromval(v) \
|
||||
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
|
||||
|
||||
|
||||
LUAI_FUNC const TValue *luaH_getint (Table *t, int key);
|
||||
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value);
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
#include "lualib.h"
|
||||
|
||||
|
||||
#define aux_getn(L,n) \
|
||||
(luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
|
||||
#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n))
|
||||
|
||||
|
||||
|
||||
#if defined(LUA_COMPAT_MAXN)
|
||||
|
@ -48,7 +48,7 @@ static int tinsert (lua_State *L) {
|
|||
case 3: {
|
||||
int i;
|
||||
pos = luaL_checkint(L, 2); /* 2nd argument is the position */
|
||||
if (pos > e) e = pos; /* `grow' array if necessary */
|
||||
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
|
||||
for (i = e; i > pos; i--) { /* move up elements */
|
||||
lua_rawgeti(L, 1, i-1);
|
||||
lua_rawseti(L, 1, i); /* t[i] = t[i-1] */
|
||||
|
@ -65,17 +65,17 @@ static int tinsert (lua_State *L) {
|
|||
|
||||
|
||||
static int tremove (lua_State *L) {
|
||||
int e = aux_getn(L, 1);
|
||||
int pos = luaL_optint(L, 2, e);
|
||||
if (!(1 <= pos && pos <= e)) /* position is outside bounds? */
|
||||
return 0; /* nothing to remove */
|
||||
int size = aux_getn(L, 1);
|
||||
int pos = luaL_optint(L, 2, size);
|
||||
if (pos != size) /* validate 'pos' if given */
|
||||
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
|
||||
lua_rawgeti(L, 1, pos); /* result = t[pos] */
|
||||
for ( ;pos<e; pos++) {
|
||||
for ( ; pos < size; pos++) {
|
||||
lua_rawgeti(L, 1, pos+1);
|
||||
lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
|
||||
}
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, 1, e); /* t[e] = nil */
|
||||
lua_rawseti(L, 1, pos); /* t[pos] = nil */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,13 +44,13 @@
|
|||
*/
|
||||
#if defined(LUA_USE_ISATTY)
|
||||
#include <unistd.h>
|
||||
#define lua_stdin_is_tty() isatty(0)
|
||||
#define lua_stdin_is_tty() isatty(0)
|
||||
#elif defined(LUA_WIN)
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
|
||||
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
|
||||
#else
|
||||
#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
|
||||
#define lua_stdin_is_tty() 1 /* assume stdin is a tty */
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -65,19 +65,19 @@
|
|||
#include <stdio.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
|
||||
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
|
||||
#define lua_saveline(L,idx) \
|
||||
if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \
|
||||
add_history(lua_tostring(L, idx)); /* add it to history */
|
||||
#define lua_freeline(L,b) ((void)L, free(b))
|
||||
#define lua_freeline(L,b) ((void)L, free(b))
|
||||
|
||||
#elif !defined(lua_readline)
|
||||
|
||||
#define lua_readline(L,b,p) \
|
||||
#define lua_readline(L,b,p) \
|
||||
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
|
||||
fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
|
||||
#define lua_saveline(L,idx) { (void)L; (void)idx; }
|
||||
#define lua_freeline(L,b) { (void)L; (void)b; }
|
||||
#define lua_saveline(L,idx) { (void)L; (void)idx; }
|
||||
#define lua_freeline(L,b) { (void)L; (void)b; }
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -222,16 +222,11 @@ static int dostring (lua_State *L, const char *s, const char *name) {
|
|||
|
||||
static int dolibrary (lua_State *L, const char *name) {
|
||||
int status;
|
||||
lua_pushglobaltable(L);
|
||||
lua_getfield(L, -1, "require");
|
||||
lua_getglobal(L, "require");
|
||||
lua_pushstring(L, name);
|
||||
status = docall(L, 1, 1);
|
||||
if (status == LUA_OK) {
|
||||
lua_setfield(L, -2, name); /* global[name] = require return */
|
||||
lua_pop(L, 1); /* remove global table */
|
||||
}
|
||||
else
|
||||
lua_remove(L, -2); /* remove global table (below error msg.) */
|
||||
status = docall(L, 1, 1); /* call 'require(name)' */
|
||||
if (status == LUA_OK)
|
||||
lua_setglobal(L, name); /* global[name] = require return */
|
||||
return report(L, status);
|
||||
}
|
||||
|
||||
|
@ -241,7 +236,6 @@ static const char *get_prompt (lua_State *L, int firstline) {
|
|||
lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
|
||||
p = lua_tostring(L, -1);
|
||||
if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
|
||||
lua_pop(L, 1); /* remove global */
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -267,7 +261,9 @@ static int pushline (lua_State *L, int firstline) {
|
|||
char *b = buffer;
|
||||
size_t l;
|
||||
const char *prmt = get_prompt(L, firstline);
|
||||
if (lua_readline(L, b, prmt) == 0)
|
||||
int readstatus = lua_readline(L, b, prmt);
|
||||
lua_pop(L, 1); /* remove result from 'get_prompt' */
|
||||
if (readstatus == 0)
|
||||
return 0; /* no input */
|
||||
l = strlen(b);
|
||||
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#define LUA_VERSION_MAJOR "5"
|
||||
#define LUA_VERSION_MINOR "2"
|
||||
#define LUA_VERSION_NUM 502
|
||||
#define LUA_VERSION_RELEASE "0"
|
||||
#define LUA_VERSION_RELEASE "3"
|
||||
|
||||
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2011 Lua.org, PUC-Rio"
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||
|
||||
|
||||
|
@ -118,6 +118,11 @@ typedef LUA_UNSIGNED lua_Unsigned;
|
|||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** RCS ident string
|
||||
*/
|
||||
extern const char lua_ident[];
|
||||
|
||||
|
||||
/*
|
||||
** state manipulation
|
||||
|
@ -412,7 +417,7 @@ struct lua_Debug {
|
|||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved.
|
||||
* Copyright (C) 1994-2013 Lua.org, PUC-Rio.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
|
|
@ -249,7 +249,7 @@ static void PrintString(const TString* ts)
|
|||
static void PrintConstant(const Proto* f, int i)
|
||||
{
|
||||
const TValue* o=&f->k[i];
|
||||
switch (ttype(o))
|
||||
switch (ttypenv(o))
|
||||
{
|
||||
case LUA_TNIL:
|
||||
printf("nil");
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
#define LUA_USE_POSIX
|
||||
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
||||
#define LUA_USE_READLINE /* needs some extra libraries */
|
||||
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */
|
||||
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
|
||||
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
|
||||
#define LUA_USE_LONGLONG /* assume support for long long */
|
||||
#endif
|
||||
|
@ -59,7 +59,7 @@
|
|||
#define LUA_USE_POSIX
|
||||
#define LUA_USE_DLOPEN /* does not need -ldl */
|
||||
#define LUA_USE_READLINE /* needs an extra library: -lreadline */
|
||||
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */
|
||||
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
|
||||
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
|
||||
#define LUA_USE_LONGLONG /* assume support for long long */
|
||||
#endif
|
||||
|
@ -236,6 +236,13 @@ inline void fwrite_wrapper(const void * ptr, size_t size, size_t count, FILE * s
|
|||
(fprintf(stderr, (s), (p)), fflush(stderr))
|
||||
|
||||
|
||||
/*
|
||||
@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is,
|
||||
** strings that are internalized. (Cannot be smaller than reserved words
|
||||
** or tags for metamethods, as these strings must be internalized;
|
||||
** #("function") = 8, #("__newindex") = 10.)
|
||||
*/
|
||||
#define LUAI_MAXSHORTLEN 40
|
||||
|
||||
|
||||
|
||||
|
@ -411,10 +418,16 @@ inline void fwrite_wrapper(const void * ptr, size_t size, size_t count, FILE * s
|
|||
#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
|
||||
|
||||
|
||||
/*
|
||||
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations
|
||||
*/
|
||||
#define l_mathop(x) (x)
|
||||
|
||||
|
||||
/*
|
||||
@@ lua_str2number converts a decimal numeric string to a number.
|
||||
@@ lua_strx2number converts an hexadecimal numeric string to a number.
|
||||
** In C99, 'strtod' do both conversions. C89, however, has no function
|
||||
** In C99, 'strtod' does both conversions. C89, however, has no function
|
||||
** to convert floating hexadecimal strings to numbers. For these
|
||||
** systems, you can leave 'lua_strx2number' undefined and Lua will
|
||||
** provide its own implementation.
|
||||
|
@ -433,8 +446,8 @@ inline void fwrite_wrapper(const void * ptr, size_t size, size_t count, FILE * s
|
|||
/* the following operations need the math library */
|
||||
#if defined(lobject_c) || defined(lvm_c)
|
||||
#include <math.h>
|
||||
#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b))
|
||||
#define luai_numpow(L,a,b) (pow(a,b))
|
||||
#define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b))
|
||||
#define luai_numpow(L,a,b) (l_mathop(pow)(a,b))
|
||||
#endif
|
||||
|
||||
/* these are quite standard operations */
|
||||
|
@ -466,66 +479,75 @@ inline void fwrite_wrapper(const void * ptr, size_t size, size_t count, FILE * s
|
|||
#define LUA_UNSIGNED unsigned LUA_INT32
|
||||
|
||||
|
||||
#if defined(LUA_CORE) /* { */
|
||||
|
||||
/*
|
||||
** Some tricks with doubles
|
||||
*/
|
||||
|
||||
#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
|
||||
|
||||
/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes
|
||||
with a DirectX idiosyncrasy */
|
||||
#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
|
||||
|
||||
#define MS_ASMTRICK
|
||||
|
||||
#else /* }{ */
|
||||
/* the next definition uses a trick that should work on any machine
|
||||
using IEEE754 with a 32-bit integer type */
|
||||
|
||||
#define LUA_IEEE754TRICK
|
||||
|
||||
/*
|
||||
** The next definitions activate some tricks to speed up the
|
||||
** conversion from doubles to integer types, mainly to LUA_UNSIGNED.
|
||||
**
|
||||
@@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a
|
||||
** DirectX idiosyncrasy.
|
||||
**
|
||||
@@ LUA_IEEE754TRICK uses a trick that should work on any machine
|
||||
** using IEEE754 with a 32-bit integer type.
|
||||
**
|
||||
@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be
|
||||
** defined when LUA_INTEGER is a 32-bit integer.
|
||||
**
|
||||
@@ LUA_IEEEENDIAN is the endianness of doubles in your machine
|
||||
** (0 for little endian, 1 for big endian); if not defined, Lua will
|
||||
** check it dynamically.
|
||||
** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK).
|
||||
**
|
||||
@@ LUA_NANTRICK controls the use of a trick to pack all types into
|
||||
** a single double value, using NaN values to represent non-number
|
||||
** values. The trick only works on 32-bit machines (ints and pointers
|
||||
** are 32-bit values) with numbers represented as IEEE 754-2008 doubles
|
||||
** with conventional endianess (12345678 or 87654321), in CPUs that do
|
||||
** not produce signaling NaN values (all NaNs are quiet).
|
||||
*/
|
||||
/* check for known architectures */
|
||||
#if defined(__i386__) || defined(__i386) || defined(__X86__) || \
|
||||
defined (__x86_64)
|
||||
#define LUA_IEEEENDIAN 0
|
||||
#elif defined(__POWERPC__) || defined(__ppc__)
|
||||
#define LUA_IEEEENDIAN 1
|
||||
#endif
|
||||
|
||||
#endif /* } */
|
||||
/* Microsoft compiler on a Pentium (32 bit) ? */
|
||||
#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
|
||||
|
||||
#endif /* } */
|
||||
|
||||
#endif /* } */
|
||||
|
||||
/* }================================================================== */
|
||||
#define LUA_MSASMTRICK
|
||||
#define LUA_IEEEENDIAN 0
|
||||
#define LUA_NANTRICK
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_NANTRICK_LE/LUA_NANTRICK_BE controls the use of a trick to
|
||||
** pack all types into a single double value, using NaN values to
|
||||
** represent non-number values. The trick only works on 32-bit machines
|
||||
** (ints and pointers are 32-bit values) with numbers represented as
|
||||
** IEEE 754-2008 doubles with conventional endianess (12345678 or
|
||||
** 87654321), in CPUs that do not produce signaling NaN values (all NaNs
|
||||
** are quiet).
|
||||
*/
|
||||
#if defined(LUA_CORE) && \
|
||||
defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
|
||||
/* pentium 32 bits? */
|
||||
#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */
|
||||
|
||||
/* little-endian architectures that satisfy those conditions */
|
||||
#if defined(__i386__) || defined(__i386) || defined(__X86__) || \
|
||||
defined(_M_IX86)
|
||||
#define LUA_IEEE754TRICK
|
||||
#define LUA_IEEELL
|
||||
#define LUA_IEEEENDIAN 0
|
||||
#define LUA_NANTRICK
|
||||
|
||||
#define LUA_NANTRICK_LE
|
||||
/* pentium 64 bits? */
|
||||
#elif defined(__x86_64) /* }{ */
|
||||
|
||||
#endif
|
||||
#define LUA_IEEE754TRICK
|
||||
#define LUA_IEEEENDIAN 0
|
||||
|
||||
#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */
|
||||
|
||||
#define LUA_IEEE754TRICK
|
||||
#define LUA_IEEEENDIAN 1
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
/* assume IEEE754 and a 32-bit integer type */
|
||||
#define LUA_IEEE754TRICK
|
||||
|
||||
#endif /* } */
|
||||
|
||||
#endif /* } */
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ typedef struct {
|
|||
const char* name;
|
||||
} LoadState;
|
||||
|
||||
static void error(LoadState* S, const char* why)
|
||||
static l_noret error(LoadState* S, const char* why)
|
||||
{
|
||||
luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why);
|
||||
luaD_throw(S->L,LUA_ERRSYNTAX);
|
||||
|
@ -38,7 +38,7 @@ static void error(LoadState* S, const char* why)
|
|||
#define LoadVector(S,b,n,size) LoadMem(S,b,n,size)
|
||||
|
||||
#if !defined(luai_verifycode)
|
||||
#define luai_verifycode(L,b,f) (f)
|
||||
#define luai_verifycode(L,b,f) /* empty */
|
||||
#endif
|
||||
|
||||
static void LoadBlock(LoadState* S, void* b, size_t size)
|
||||
|
@ -90,7 +90,7 @@ static void LoadCode(LoadState* S, Proto* f)
|
|||
LoadVector(S,f->code,n,sizeof(Instruction));
|
||||
}
|
||||
|
||||
static Proto* LoadFunction(LoadState* S);
|
||||
static void LoadFunction(LoadState* S, Proto* f);
|
||||
|
||||
static void LoadConstants(LoadState* S, Proto* f)
|
||||
{
|
||||
|
@ -117,13 +117,18 @@ static void LoadConstants(LoadState* S, Proto* f)
|
|||
case LUA_TSTRING:
|
||||
setsvalue2n(S->L,o,LoadString(S));
|
||||
break;
|
||||
default: lua_assert(0);
|
||||
}
|
||||
}
|
||||
n=LoadInt(S);
|
||||
f->p=luaM_newvector(S->L,n,Proto*);
|
||||
f->sizep=n;
|
||||
for (i=0; i<n; i++) f->p[i]=NULL;
|
||||
for (i=0; i<n; i++) f->p[i]=LoadFunction(S);
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
f->p[i]=luaF_newproto(S->L);
|
||||
LoadFunction(S,f->p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadUpvalues(LoadState* S, Proto* f)
|
||||
|
@ -162,10 +167,8 @@ static void LoadDebug(LoadState* S, Proto* f)
|
|||
for (i=0; i<n; i++) f->upvalues[i].name=LoadString(S);
|
||||
}
|
||||
|
||||
static Proto* LoadFunction(LoadState* S)
|
||||
static void LoadFunction(LoadState* S, Proto* f)
|
||||
{
|
||||
Proto* f=luaF_newproto(S->L);
|
||||
setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
|
||||
f->linedefined=LoadInt(S);
|
||||
f->lastlinedefined=LoadInt(S);
|
||||
f->numparams=LoadByte(S);
|
||||
|
@ -175,8 +178,6 @@ static Proto* LoadFunction(LoadState* S)
|
|||
LoadConstants(S,f);
|
||||
LoadUpvalues(S,f);
|
||||
LoadDebug(S,f);
|
||||
S->L->top--;
|
||||
return f;
|
||||
}
|
||||
|
||||
/* the code below must be consistent with the code in luaU_header */
|
||||
|
@ -201,9 +202,10 @@ static void LoadHeader(LoadState* S)
|
|||
/*
|
||||
** load precompiled chunk
|
||||
*/
|
||||
Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
|
||||
Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
|
||||
{
|
||||
LoadState S;
|
||||
Closure* cl;
|
||||
if (*name=='@' || *name=='=')
|
||||
S.name=name+1;
|
||||
else if (*name==LUA_SIGNATURE[0])
|
||||
|
@ -214,7 +216,19 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name)
|
|||
S.Z=Z;
|
||||
S.b=buff;
|
||||
LoadHeader(&S);
|
||||
return luai_verifycode(L,buff,LoadFunction(&S));
|
||||
cl=luaF_newLclosure(L,1);
|
||||
setclLvalue(L,L->top,cl); incr_top(L);
|
||||
cl->l.p=luaF_newproto(L);
|
||||
LoadFunction(&S,cl->l.p);
|
||||
if (cl->l.p->sizeupvalues != 1)
|
||||
{
|
||||
Proto* p=cl->l.p;
|
||||
cl=luaF_newLclosure(L,cl->l.p->sizeupvalues);
|
||||
cl->l.p=p;
|
||||
setclLvalue(L,L->top-1,cl);
|
||||
}
|
||||
luai_verifycode(L,buff,cl->l.p);
|
||||
return cl;
|
||||
}
|
||||
|
||||
#define MYINT(s) (s[0]-'0')
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "lzio.h"
|
||||
|
||||
/* load one chunk; from lundump.c */
|
||||
LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
|
||||
LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
|
||||
|
||||
/* make header; from lundump.c */
|
||||
LUAI_FUNC void luaU_header (lu_byte* h);
|
||||
|
|
|
@ -59,10 +59,15 @@ int luaV_tostring (lua_State *L, StkId obj) {
|
|||
static void traceexec (lua_State *L) {
|
||||
CallInfo *ci = L->ci;
|
||||
lu_byte mask = L->hookmask;
|
||||
if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
|
||||
resethookcount(L);
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1);
|
||||
int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
|
||||
if (counthook)
|
||||
resethookcount(L); /* reset count */
|
||||
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
|
||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||
return; /* do not call hook again (VM yielded, so it did not move) */
|
||||
}
|
||||
if (counthook)
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */
|
||||
if (mask & LUA_MASKLINE) {
|
||||
Proto *p = ci_func(ci)->p;
|
||||
int npc = pcRel(ci->u.l.savedpc, p);
|
||||
|
@ -70,11 +75,15 @@ static void traceexec (lua_State *L) {
|
|||
if (npc == 0 || /* call linehook when enter a new function, */
|
||||
ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */
|
||||
newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */
|
||||
luaD_hook(L, LUA_HOOKLINE, newline);
|
||||
luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */
|
||||
}
|
||||
L->oldpc = ci->u.l.savedpc;
|
||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||
if (counthook)
|
||||
L->hookcount = 1; /* undo decrement to zero */
|
||||
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
|
||||
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
||||
ci->func = L->top - 1; /* protect stack below results */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +97,6 @@ static void callTM (lua_State *L, const TValue *f, const TValue *p1,
|
|||
setobj2s(L, L->top++, p2); /* 2nd argument */
|
||||
if (!hasres) /* no result? 'p3' is third argument */
|
||||
setobj2s(L, L->top++, p3); /* 3rd argument */
|
||||
luaD_checkstack(L, 0);
|
||||
/* metamethod may yield only when called from Lua code */
|
||||
luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
|
||||
if (hasres) { /* if has result, move it to its place */
|
||||
|
@ -257,7 +265,8 @@ int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) {
|
|||
case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
|
||||
case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
|
||||
case LUA_TLCF: return fvalue(t1) == fvalue(t2);
|
||||
case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2));
|
||||
case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2));
|
||||
case LUA_TLNGSTR: return luaS_eqlngstr(rawtsvalue(t1), rawtsvalue(t2));
|
||||
case LUA_TUSERDATA: {
|
||||
if (uvalue(t1) == uvalue(t2)) return 1;
|
||||
else if (L == NULL) return 0;
|
||||
|
@ -292,7 +301,7 @@ void luaV_concat (lua_State *L, int total) {
|
|||
else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
|
||||
(void)tostring(L, top - 2); /* result is first operand */
|
||||
else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
|
||||
setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */
|
||||
setobjs2s(L, top - 2, top - 1); /* result is second op. */
|
||||
}
|
||||
else {
|
||||
/* at least two non-empty string values; get as many as possible */
|
||||
|
@ -393,7 +402,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
|||
int nup = p->sizeupvalues;
|
||||
Upvaldesc *uv = p->upvalues;
|
||||
int i;
|
||||
Closure *ncl = luaF_newLclosure(L, p);
|
||||
Closure *ncl = luaF_newLclosure(L, nup);
|
||||
ncl->l.p = p;
|
||||
setclLvalue(L, ra, ncl); /* anchor new closure in stack */
|
||||
for (i = 0; i < nup; i++) { /* fill in its upvalues */
|
||||
if (uv[i].instack) /* upvalue refers to local variable? */
|
||||
|
@ -458,7 +468,7 @@ void luaV_finishOp (lua_State *L) {
|
|||
L->top = ci->top; /* adjust results */
|
||||
break;
|
||||
}
|
||||
case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
|
||||
case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
|
||||
break;
|
||||
default: lua_assert(0);
|
||||
}
|
||||
|
@ -499,7 +509,11 @@ void luaV_finishOp (lua_State *L) {
|
|||
|
||||
#define Protect(x) { {x;}; base = ci->u.l.base; }
|
||||
|
||||
#define checkGC(L,c) Protect(luaC_condGC(L, c); luai_threadyield(L);)
|
||||
#define checkGC(L,c) \
|
||||
Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
|
||||
luaC_step(L); \
|
||||
L->top = ci->top;}) /* restore top */ \
|
||||
luai_threadyield(L); )
|
||||
|
||||
|
||||
#define arith_op(op,tm) { \
|
||||
|
@ -592,11 +606,7 @@ void luaV_execute (lua_State *L) {
|
|||
sethvalue(L, ra, t);
|
||||
if (b != 0 || c != 0)
|
||||
luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c));
|
||||
checkGC(L,
|
||||
L->top = ra + 1; /* limit of live values */
|
||||
luaC_step(L);
|
||||
L->top = ci->top; /* restore top */
|
||||
)
|
||||
checkGC(L, ra + 1);
|
||||
)
|
||||
vmcase(OP_SELF,
|
||||
StkId rb = RB(i);
|
||||
|
@ -648,10 +658,7 @@ void luaV_execute (lua_State *L) {
|
|||
ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
|
||||
rb = b + base;
|
||||
setobjs2s(L, ra, rb);
|
||||
checkGC(L,
|
||||
L->top = (ra >= rb ? ra + 1 : rb); /* limit of live values */
|
||||
luaC_step(L);
|
||||
)
|
||||
checkGC(L, (ra >= rb ? ra + 1 : rb));
|
||||
L->top = ci->top; /* restore top */
|
||||
)
|
||||
vmcase(OP_JMP,
|
||||
|
@ -829,11 +836,7 @@ void luaV_execute (lua_State *L) {
|
|||
pushclosure(L, p, cl->upvals, base, ra); /* create a new one */
|
||||
else
|
||||
setclLvalue(L, ra, ncl); /* push cashed closure */
|
||||
checkGC(L,
|
||||
L->top = ra + 1; /* limit of live values */
|
||||
luaC_step(L);
|
||||
L->top = ci->top; /* restore top */
|
||||
)
|
||||
checkGC(L, ra + 1);
|
||||
)
|
||||
vmcase(OP_VARARG,
|
||||
int b = GETARG_B(i) - 1;
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2))
|
||||
|
||||
#define luaV_rawequalobj(t1,t2) \
|
||||
(ttisequal(t1,t2) && luaV_equalobj_(NULL,t1,t2))
|
||||
#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2)
|
||||
|
||||
|
||||
/* not to called directly */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** a generic input stream interface
|
||||
** Buffered streams
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
|
|
@ -803,22 +803,42 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m
|
|||
std::vector<attack_type> attacks = u->attacks();
|
||||
std::vector<attack_type>::iterator itor;
|
||||
|
||||
filter = cfg.child("primary_attack");
|
||||
if(!filter.null()) {
|
||||
for(itor = attacks.begin(); itor != attacks.end(); ++itor){
|
||||
if(itor->matches_filter(filter.get_parsed_config())) {
|
||||
primary = &*itor;
|
||||
break;
|
||||
}
|
||||
// death and victory animations are handled here because usually
|
||||
// the code iterates through all the unit's attacks
|
||||
// but in these two specific cases we need to create dummy attacks
|
||||
// to fire correctly certain animations
|
||||
// this is especially evident with the Wose's death animations
|
||||
if (cfg["flag"] == "death" || cfg["flag"] == "victory") {
|
||||
filter = cfg.child("primary_attack");
|
||||
if(!filter.null()) {
|
||||
attack_type dummy_primary = static_cast<attack_type>(filter.get_config());
|
||||
primary = &dummy_primary;
|
||||
}
|
||||
filter = cfg.child("secondary_attack");
|
||||
if(!filter.null()) {
|
||||
attack_type dummy_secondary = static_cast<attack_type>(filter.get_config());
|
||||
secondary = &dummy_secondary;
|
||||
}
|
||||
}
|
||||
|
||||
filter = cfg.child("secondary_attack");
|
||||
if(!filter.null()) {
|
||||
for(itor = attacks.begin(); itor != attacks.end(); ++itor){
|
||||
if(itor->matches_filter(filter.get_parsed_config())) {
|
||||
secondary = &*itor;
|
||||
break;
|
||||
else {
|
||||
filter = cfg.child("primary_attack");
|
||||
if(!filter.null()) {
|
||||
for(itor = attacks.begin(); itor != attacks.end(); ++itor){
|
||||
if(itor->matches_filter(filter.get_parsed_config())) {
|
||||
primary = &*itor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filter = cfg.child("secondary_attack");
|
||||
if(!filter.null()) {
|
||||
for(itor = attacks.begin(); itor != attacks.end(); ++itor){
|
||||
if(itor->matches_filter(filter.get_parsed_config())) {
|
||||
secondary = &*itor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue