source: trunk/src/lua/lua_nova.cc @ 262

Last change on this file since 262 was 217, checked in by epyon, 12 years ago
  • lua/nova - almost complete reimplementation of "core" from FPC Valkyrie
  • lua/state - nova loaded by default
  • object - prototype reference caching
File size: 22.6 KB
Line 
1// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/lua/lua_nova.hh"
8
9#include "nv/lua/lua_raw.hh"
10
11const char* NV_STATE      = "NV_STATE";
12const char* NV_BLUEPRINTS = "NV_BLUEPRINTS";
13
14// static nv::lua::state* nova_get_state( lua_State * L )
15// {
16//      int stack = lua_gettop( L );
17//      nv::lua::state* result = nullptr;
18//      lua_getfield( L, LUA_REGISTRYINDEX, NV_STATE );
19//      result = static_cast< nv::lua::state* >( lua_touserdata( L, -1 ) );
20//      lua_settop( L, stack );
21//      return result;
22// }
23
24// BLUEPRINTS
25
26static bool nova_blueprint_exists( lua_State * L, int index )
27{
28        lua_getfield( L, LUA_REGISTRYINDEX, NV_BLUEPRINTS );
29        lua_pushvalue( L, index );
30        lua_rawget( L, -2 );
31        bool result = lua_istable( L, -1 );
32        lua_pop( L, 2 );
33        return result;
34}
35
36// static void nova_blueprint_push( lua_State * L, int index )
37// {
38//      lua_getfield( L, LUA_REGISTRYINDEX, NV_BLUEPRINTS );
39//      lua_pushvalue( L, index );
40//      lua_rawget( L, -2 );
41//      if ( !lua_istable( L, -1 ) )
42//      {
43//              luaL_error( L, "lua.nova - blueprint \"%s\" doesn't exist!", lua_tolstring( L, index, 0 ) );
44//      }
45//      lua_replace( L, -2 );
46//      lua_pop( L, 1 );
47// }
48
49static int nova_apply_blueprint( lua_State * L ); // forward
50
51// returns true if value modified
52static bool nova_check_type_raw( lua_State * L, int iid, int ifield, int ivalue, int itype )
53{
54        iid    = lua_absindex( L, iid );
55        ifield = lua_absindex( L, ifield );
56        ivalue = lua_absindex( L, ivalue );
57        itype  = lua_absindex( L, itype );
58
59        switch ( lua_type( L, itype ) )
60        {
61        case LUA_TFUNCTION :
62                lua_pushvalue( L, itype );  // type function
63                lua_pushvalue( L, iid );    // identifier
64                lua_pushvalue( L, ifield ); // field name
65                lua_pushvalue( L, ivalue ); // field value
66                lua_call( L, 3, 1 );
67                if ( lua_isnoneornil( L, -1 ) )
68                {
69                        lua_pop( L, 1 );
70                }
71                else
72                {
73                        return true;
74                }
75        case LUA_TSTRING :
76                if ( lua_type( L, ivalue ) != LUA_TTABLE )
77                {
78                        luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, table of blueprint \"%s\" expected, %s found!", lua_tolstring( L, iid, 0 ), lua_tolstring( L, ifield, 0 ), lua_tolstring( L, itype, 0 ), lua_typename( L, lua_type( L, ivalue ) ) );
79                }
80                lua_pushcfunction( L, nova_apply_blueprint );
81                lua_pushvalue( L, ivalue );
82                lua_pushvalue( L, itype );
83                lua_pushvalue( L, iid );
84                lua_pushstring( L, "." );
85                lua_pushvalue( L, ifield );
86                lua_concat( L, 3 );
87                lua_call( L, 3, 0 );
88        case LUA_TNUMBER :
89                if (lua_tointeger( L, itype ) != lua_type( L, ivalue ) && lua_tointeger( L, itype ) > 0)
90                {
91                        luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, %s expected, %s found!", lua_tolstring( L, iid, 0 ), lua_tolstring( L, ifield, 0 ), lua_typename( L, lua_tointeger( L, itype ) ), lua_typename( L, lua_type( L, ivalue ) ) );
92                }
93
94        }
95        return false;
96}
97
98static void nova_apply_blueprint_values_raw( lua_State * L, int ibase, int iproto, int iset, int iid )
99{
100        ibase  = lua_absindex( L, ibase );
101        iproto = lua_absindex( L, iproto );
102        iset   = lua_absindex( L, iset );
103        iid    = lua_absindex( L, iid );
104
105        lua_pushnil( L );
106        while ( lua_next( L, iproto ) != 0 )
107        {
108                // Key -2, Value -1
109                int ikey   = lua_absindex( L, -2 );
110                int ivalue = lua_absindex( L, -1 );
111
112                // Base[Key]
113                lua_pushvalue( L, ikey );
114                lua_rawget( L, ibase );
115                bool present = !lua_isnil( L, -1 );
116                lua_pop( L, 1 );
117
118                if (lua_type( L, ivalue ) == LUA_TTABLE)
119                {
120                        // Value[1]
121                        lua_rawgeti( L, ivalue, 1 );
122                        bool mandatory = lua_toboolean( L, -1 ) != 0;
123                        bool nested    = lua_type( L, -1 ) == LUA_TTABLE;
124                        lua_pop( L, 1 );
125
126                        if (!present)
127                        {
128                                if (mandatory)
129                                {
130                                        luaL_error( L, "lua.nova - %s has no required field \"%s\"!", lua_tolstring( L, iid, 0 ), lua_tolstring( L, -2, 0 ) );
131                                }
132                                else
133                                {
134                                        lua_pushvalue( L, ikey ); // push Key
135                                        lua_rawgeti( L, ivalue, 3 ); // Value[3]
136                                        if ( lua_type( L, -1 ) == LUA_TTABLE )
137                                        {
138                                                nlua_shallowcopy( L, -1 );
139                                                lua_replace( L, -2 );
140                                        }
141                                        lua_rawset( L, ibase ); // Base[Key] =
142                                }
143                        }
144
145                        if (nested)
146                        {
147                                lua_rawgeti( L, ivalue, 1 ); // v[1]
148                                lua_pushvalue( L, ikey );  // Key
149                                lua_rawget( L, ibase );  // Base[Key]
150                                lua_rawget( L, -2 );     // v[1][Base[Key]]
151                                lua_replace( L, -2 );    // down to 1 stack
152                                if (!lua_isnil( L, -1 ))
153                                {
154                                        nova_apply_blueprint_values_raw( L, ibase, -1, iset, iid );
155                                }
156                                lua_pop( L, 1 );
157                        }
158                        else
159                        if (present)
160                        {
161                                lua_rawgeti( L, ivalue, 2 ); // Value[2]
162                                lua_pushvalue( L, ikey );  // Key
163                                lua_rawget( L, ibase );  // Base[Key]
164                                if ( nova_check_type_raw( L, iid, ikey, -1, -2 ) )
165                                {
166                                        lua_pushvalue( L, ikey );  // Key
167                                        lua_insert( L, -2 );
168                                        lua_rawset( L, ibase );
169                                }
170                                lua_pop( L, 2 );
171                        }
172                }
173                else
174                {
175                        if (present) luaL_error( L, "lua.nova - %s - field \"%s\" cannot be redefined!", lua_tolstring( L, iid, 0 ), lua_tolstring( L, ikey, 0 ) );
176                        // non-table entries get forced copied
177                        lua_pushvalue( L, ikey ); // push Key
178                        lua_pushvalue( L, ivalue ); // push Value
179                        lua_rawset( L, ibase ); // Base[Key] =
180                }
181                lua_pushvalue( L, ikey ); // Key
182                lua_pushnil( L );
183                lua_rawset( L, iset );  // Set[Key] = nil
184                lua_pop( L, 1 );
185        }
186}
187
188static int nova_apply_blueprint_values( lua_State * L )
189{
190        luaL_checktype( L, 1, LUA_TTABLE );  // base
191        luaL_checktype( L, 2, LUA_TTABLE );  // prototype
192        luaL_checktype( L, 3, LUA_TTABLE );  // set
193        luaL_checktype( L, 4, LUA_TSTRING ); // ident
194        lua_settop( L, 4 );
195        nova_apply_blueprint_values_raw( L, 1, 2, 3, 4 );
196        return 0;
197}
198
199static void nova_apply_blueprint_raw( lua_State * L, int ibase, int iproto, int iid )
200{
201        ibase    = lua_absindex( L, ibase );
202        iproto   = lua_absindex( L, iproto );
203        iid      = lua_absindex( L, iid );
204        nlua_tokeyset( L, ibase );
205        int iset = lua_absindex( L, -1 );
206
207        nova_apply_blueprint_values_raw( L, ibase, iproto, iset, iid );
208
209        lua_pushnil( L );
210        while ( lua_next( L, iset ) != 0 )
211        {
212                luaL_error( L, "lua.nova - %s has unknown field \"%s\"!", lua_tolstring( L, 3, 0 ), lua_tolstring( L, -2, 0 ) );
213                lua_pop(L, 1);
214        }
215        lua_pop(L, 1);
216}
217
218static int nova_apply_blueprint( lua_State * L )
219{
220        luaL_checktype( L, 1, LUA_TTABLE );  // base
221        if ( lua_type( L, 2 ) == LUA_TSTRING )
222        {
223                lua_getfield( L, LUA_REGISTRYINDEX, NV_BLUEPRINTS );
224                lua_pushvalue( L, 2 );
225                lua_rawget( L, -2 );
226                lua_replace( L, 2 );
227        }
228        luaL_checktype( L, 2, LUA_TTABLE );  // prototype
229        luaL_checktype( L, 3, LUA_TSTRING ); // ident
230        lua_settop( L, 3 );
231        nova_apply_blueprint_raw( L, 1, 2, 3 );
232        return 1;
233}
234
235// stack[1] - table
236// up[1]    - blueprint_id
237// up[2]    - inherit_id
238static int nova_register_blueprint_closure( lua_State * L )
239{
240        luaL_checktype( L, 1, LUA_TTABLE );
241        lua_getfield( L, LUA_REGISTRYINDEX, NV_BLUEPRINTS );
242
243        if ( lua_isnil( L, lua_upvalueindex(2) ) )
244        {
245                lua_pushvalue( L, lua_upvalueindex(1) );
246                lua_pushvalue( L, 1 );
247                lua_rawset( L, -3 );
248        }
249        else
250        {
251                lua_pushvalue( L, lua_upvalueindex(1) );
252                lua_pushvalue( L, lua_upvalueindex(2) );
253                lua_rawget( L, -3 );
254                nlua_shallowcopy( L, -1 );
255                lua_replace( L, -2 );
256                nlua_shallowmerge( L, 1 );
257                lua_rawset( L, -3 );
258        }
259
260        lua_pop( L, 1 );
261        return 0;
262}
263
264static int nova_register_blueprint( lua_State * L )
265{
266        luaL_checktype( L, 1, LUA_TSTRING );
267        if ( nova_blueprint_exists( L, 1 ) )
268        {
269                luaL_error( L, "lua.nova - blueprint \"%s\" already registered!", lua_tolstring( L, 1, 0 ) );
270        }
271        if ( lua_gettop( L ) > 1 )
272        {
273                luaL_checktype( L, 2, LUA_TSTRING );
274                if ( !nova_blueprint_exists( L, 2 ) )
275                {
276                        luaL_error( L, "lua.nova - blueprint \"%s\" doesn't exist!", lua_tolstring( L, 2, 0 ) );
277                }
278        }
279        else
280        {
281                lua_pushnil( L );
282        }
283        lua_pushcclosure( L, nova_register_blueprint_closure, 2 );
284        return 1;
285}
286
287
288static int nova_array_register( lua_State * L )
289{
290        // storage.__counter++
291        lua_pushstring( L, "__counter" );
292        lua_pushvalue( L, -1 );
293        lua_rawget( L, 1 );
294        int count = 0;
295        if ( !lua_isnil( L, -1 ) ) count = lua_tointeger( L, -1 );
296        lua_pop( L, 1 );
297        count++;
298        lua_pushinteger( L, count );
299        lua_rawset( L, 1 );
300
301        // element.nid = __counter
302        lua_pushstring( L, "nid" );
303        lua_pushinteger( L, count );
304        lua_rawset( L, 2 );
305
306        // storage[ __counter ] = element
307        lua_pushinteger( L, count );
308        lua_pushvalue( L, 2 );
309        lua_rawset( L, 1 );
310
311        // return nid
312        lua_pushinteger( L, count );
313        return 1;
314}
315
316static int nova_register( lua_State * L )
317{
318        nova_array_register(L);
319
320        // element.id = element.id
321        lua_pushstring( L, "id" );
322        lua_rawget( L, 2 );
323        if ( lua_isnil( L, -1 ) )
324                luaL_error( L, "lua.nova - element without id!" );
325       
326        // storage[element.id] = element
327        lua_pushvalue( L, -1 );
328        lua_pushvalue( L, 2 );
329        lua_rawset( L, 1 );
330
331        // core.define( element.id, element.nid )
332        //LuaSystem.FDefines[ iID ] := lua_tointeger( L, 3 );
333
334        // return id
335        return 1;
336}
337
338static int nova_declare( lua_State * L )
339{
340        if ( lua_gettop( L ) <  1 ) return 0;
341        if ( lua_gettop( L ) == 1 ) lua_pushboolean( L, false );
342        lua_settop( L, 2 );
343        lua_pushglobaltable( L );
344        lua_insert( L, 1 );
345        lua_rawset( L, -3 );
346        return 0;
347}
348
349static int nova_iif( lua_State * L )
350{
351        lua_settop( L, lua_toboolean( L, 1 ) ? 2 : 3 );
352        return 1;
353}
354
355static int nova_create_seq_function_closure( lua_State * L )
356{
357        int fc   = lua_tointeger( L, lua_upvalueindex( 1 ) );
358        int args = lua_gettop( L );
359        for ( int fi = 1; fi <= fc; fi++ )
360        {
361                lua_pushvalue( L, lua_upvalueindex( fi + 1 ) );
362                for ( int i = 1; i <= args; i++ )
363                        lua_pushvalue( L, i );
364                lua_call( L, args, 0 );
365        }
366        return 0;
367}
368
369static int nova_create_seq_function( lua_State * L )
370{
371        int count    = lua_gettop( L );
372        int upvalues = count;
373        for ( int i = 1; i <= count; i++ )
374                if ( lua_isnoneornil( L, i ) )
375                        upvalues--;
376                else
377                        luaL_checktype( L, i, LUA_TFUNCTION );
378
379        if ( upvalues == 0 ) return 0;
380
381        lua_pushinteger( L, upvalues );
382        for ( int i = 1; i <= count; i++ )
383                if ( !lua_isnoneornil( L, i ) )
384                        lua_pushvalue( L, i );
385
386        if ( upvalues == 1 ) return 1;
387        lua_pushcclosure( L, nova_create_seq_function_closure, upvalues + 1 );
388        return 1;
389}
390
391static int nova_type_FLAGS( lua_State * L )
392{
393        if ( lua_type( L, 3 ) != LUA_TTABLE ) luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, flags expected, %s found!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ), lua_typename( L, lua_type( L, 3 ) ) );
394        nlua_toset( L, 3 );
395        return 1;
396}
397
398static int nova_type_BLUEPRINT( lua_State * L )
399{
400        if ( lua_type( L, 3 ) != LUA_TSTRING ) luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, blueprint id expected, %s found!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ), lua_typename( L, lua_type( L, 3 ) ) );
401        if ( !nova_blueprint_exists( L, 3 ) )  luaL_error( L, "lua.nova - \"%s.%s\" - blueprint \"%s\" isn't valid!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ), lua_tolstring( L, 3, 0 ) );
402        return 0;
403}
404
405static int nova_type_ARRAY_closure( lua_State * L )
406{
407        if ( lua_type( L, 3 ) != LUA_TTABLE ) luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, ARRAY expected, %s found!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ), lua_typename( L, lua_type( L, 3 ) ) );
408        lua_settop( L, 3 );
409        lua_pushvalue( L, lua_upvalueindex(1) ); // push type index 4
410
411        lua_pushvalue( L, 1 );
412        lua_pushstring( L, "." );
413        lua_pushvalue( L, 2 );
414        lua_concat( L, 3 ); // new ident index 5
415
416        lua_pushnil(L);
417        while ( lua_next( L, 3 ) != 0 )
418        {
419                // key (index -2), value (index -1)
420                if ( lua_type( L, -2 ) != LUA_TNUMBER ) luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, ARRAY expected, field found!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ) );
421                if ( nova_check_type_raw( L, 5, -2, -1, 4 ) )
422                {
423                        lua_pushvalue( L, -3 );  // Key
424                        lua_insert( L, -2 );
425                        lua_rawset( L, -3 ); // update Value
426                }
427                lua_pop( L, 1 );
428        }
429        return 0;
430}
431
432static int nova_type_ARRAY( lua_State * L )
433{
434        if ( lua_gettop( L ) != 1 ) luaL_error( L, "lua.nova - Misuse of nova.TARRAY type - usage is core.TARRAY( type )" );
435        lua_pushcclosure( L, nova_type_ARRAY_closure, 1 );
436        return 1;
437}
438
439static int nova_type_MAP_closure( lua_State * L )
440{
441        if ( lua_type( L, 3 ) != LUA_TTABLE ) luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, MAP expected, %s found!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ), lua_typename( L, lua_type( L, 3 ) ) );
442
443        lua_settop( L, 3 );
444        lua_pushvalue( L, lua_upvalueindex(1) ); // push key type index 4
445        lua_pushvalue( L, lua_upvalueindex(2) ); // push value type index 5
446
447        lua_pushvalue( L, 1 );
448        lua_pushstring( L, "." );
449        lua_pushvalue( L, 2 );
450        lua_concat( L, 3 ); // new ident index 6
451
452        lua_pushnil(L);
453        while ( lua_next( L, 3 ) != 0 )
454        {
455                // key (index -2), value (index -1)
456                if ( nova_check_type_raw( L, 6, -2, -2, 4 ) ) luaL_error( L, "lua.nova - \"%s.%s\" - KEY type can't be mutable!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ) );
457                if ( nova_check_type_raw( L, 6, -2, -1, 5 ) )
458                {
459                        lua_pushvalue( L, -3 );  // Key
460                        lua_insert( L, -2 );
461                        lua_rawset( L, -3 ); // update Value
462                }
463                lua_pop( L, 1 );
464        }
465        return 0;
466}
467
468static int nova_type_MAP( lua_State * L )
469{
470        if ( lua_gettop( L ) != 2 ) luaL_error( L, "lua.nova - Misuse of nova.TMAP type - usage is core.TMAP( keytype, valuetype )" );
471        lua_pushcclosure( L, nova_type_MAP_closure, 2 );
472        return 1;
473}
474
475static int nova_type_ID_closure( lua_State * L )
476{
477        if ( lua_type( L, 3 ) != LUA_TSTRING ) luaL_error( L, "lua.nova - \"%s.%s\" - type mismatch, ID expected, %s found!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ), lua_typename( L, lua_type( L, 3 ) ) );
478        lua_settop( L, 3 );
479        lua_pushvalue( L, lua_upvalueindex(1) ); // push type index 4
480        if ( lua_type( L, -1 ) == LUA_TSTRING )
481        {
482                lua_pushglobaltable( L );
483                lua_pushvalue( L, -2 );
484                lua_rawget( L, -2 );
485                lua_replace( L, -2 );
486        }
487        if ( lua_type( L, -1 ) != LUA_TTABLE ) luaL_error( L, "lua.nova - not a valid storage table in TID!" );
488        lua_pushvalue( L, 3 );
489        lua_rawget( L, -2 );
490        if ( lua_isnoneornil( L, -1 ) ) luaL_error( L, "lua.nova - \"%s.%s\" - valid ID expected!", lua_tolstring( L, 1, 0 ), lua_tolstring( L, 2, 0 ) );
491        return 0;
492}
493
494static int nova_type_ID( lua_State * L )
495{
496        if ( lua_gettop( L ) != 1 ) luaL_error( L, "lua.nova - Misuse of nova.TID type - usage is core.TID( storage )" );
497        lua_pushcclosure( L, nova_type_ID_closure, 1 );
498        return 1;
499}
500
501static int nova_create_constructor_impl( lua_State * L )
502{
503        luaL_checktype( L, 1, LUA_TTABLE );
504        lua_pushvalue( L, lua_upvalueindex( 1 ) ); // id
505        //ident = vlua_tostring( L, -1 );
506        //if LuaSystem.Defines.Exists( ident ) then
507        //luaL_error( L, 'Redefinition of id "%s"!', lua_tolstring( L, -1, nil ) );
508        lua_setfield( L, 1, "id" );
509        lua_getfield( L, 1, "blueprint" );
510
511        if ( lua_isnil( L, -1 ) && (!lua_isnoneornil( L, lua_upvalueindex( 3 ) ) ) )  // blueprint
512        {
513                lua_pushvalue( L, lua_upvalueindex( 3 ) );
514                lua_replace( L, -2 );
515        }
516        if ( lua_isnil( L, -1 ) ) // storage.__blueprint
517        {
518                lua_getfield( L, lua_upvalueindex( 2 ), "__blueprint" );
519                lua_replace( L, -2 );
520        }
521        if ( !lua_isnil( L, -1 ) )
522        {
523                lua_getfield( L, lua_upvalueindex( 2 ), "__name" ); // storage.__name
524                lua_pushfstring( L, "%s[%s]", lua_tostring( L, -1 ), lua_tostring( L, lua_upvalueindex( 1 ) ) );
525                lua_replace( L, -2 );
526
527                lua_pushcfunction( L, nova_apply_blueprint );
528                lua_pushvalue( L, 1 );
529                lua_pushvalue( L, -4 );
530                lua_pushvalue( L, -4 );
531                lua_call( L, 3, 0 );
532                lua_pop( L, 2 );
533        }
534
535        lua_pushcfunction( L, nova_register );
536        lua_pushvalue( L, lua_upvalueindex( 2 ) );
537        lua_pushvalue( L, 1 );
538        lua_call( L, 2, 0 );
539
540        if ( !lua_isnoneornil( L, lua_upvalueindex( 4 ) ) ) // constructor
541        {
542                lua_pushvalue( L, lua_upvalueindex( 4 ) ); // constructor
543                lua_pushvalue( L, 1 );
544                lua_call( L, 1, 0 );
545        }
546
547        lua_pushvalue( L, lua_upvalueindex( 1 ) ); // id
548        return 1;
549}
550
551static int nova_create_constructor_closure( lua_State * L )
552{
553        luaL_checktype( L, 1, LUA_TSTRING );
554        if ( lua_gettop( L ) > 1 )
555        {
556                lua_settop( L, 2 );
557                luaL_checktype( L, 2, LUA_TSTRING );
558                lua_pushvalue( L, lua_upvalueindex( 1 ) );
559                lua_insert( L, -2 );
560        }
561        else
562        {
563                lua_settop( L, 1 );
564                lua_pushvalue( L, lua_upvalueindex( 1 ) );
565                lua_pushvalue( L, lua_upvalueindex( 2 ) );
566        }
567        lua_pushvalue( L, lua_upvalueindex( 3 ) );
568        lua_settop( L, 4 );
569
570        lua_pushcclosure(L, nova_create_constructor_impl, 4);
571        return 1;
572}
573
574static int nova_create_constructor( lua_State * L )
575{
576        if ( lua_type( L, 1 ) == LUA_TSTRING )
577        {
578                lua_getglobal( L, lua_tostring( L, 1 ) );
579                lua_replace( L, 1 );
580        }
581        luaL_checktype( L, 1, LUA_TTABLE );
582        if ( !lua_isnoneornil( L, 2 ) ) luaL_checktype( L, 2, LUA_TSTRING );
583        if ( !lua_isnoneornil( L, 3 ) ) luaL_checktype( L, 3, LUA_TFUNCTION );
584        lua_settop( L, 3 );
585        lua_pushcclosure(L, nova_create_constructor_closure, 3);
586        return 1;
587}
588
589static int nova_create_array_constructor_closure( lua_State * L )
590{
591        bool blueprint = true;
592        luaL_checktype( L, 1, LUA_TTABLE );
593
594        lua_getfield( L, lua_upvalueindex( 1 ), "__blueprint" );
595        if ( lua_type( L, -1 ) == LUA_TBOOLEAN ) blueprint = lua_toboolean( L, -1 ) != 0;
596        lua_pop( L, 1 );
597
598        if ( blueprint )
599        {
600                lua_getfield( L, 1, "blueprint" );
601                if ( lua_isnil( L, -1 ) && (!lua_isnoneornil( L, lua_upvalueindex( 2 ) )) ) // blueprint
602                {
603                        lua_pushvalue( L, lua_upvalueindex( 2 ) );
604                        lua_replace( L, -2 );
605                }
606
607                if ( lua_isnil( L, -1 ) ) // storage.__blueprint
608                {
609                        lua_getfield( L, lua_upvalueindex( 1 ), "__blueprint" );
610                        lua_replace( L, -2 );
611                }
612
613                if ( !lua_isnil( L, -1 ) && ( lua_type( L, -1 ) != LUA_TBOOLEAN ) )
614                {
615                        lua_getfield( L, lua_upvalueindex( 1 ), "__name" ); // storage.__name
616                        lua_pushfstring( L, "%s[%d]", lua_tostring( L, -1 ), lua_objlen(L,lua_upvalueindex( 1 ))+1 );
617                        lua_replace( L, -2 );
618
619                        lua_pushcfunction( L, nova_apply_blueprint );
620                        lua_pushvalue( L, 1 );
621                        lua_pushvalue( L, -4 );
622                        lua_pushvalue( L, -4 );
623                        lua_call( L, 3, 0 );
624                        lua_pop( L, 2 );
625                }
626        }
627
628        lua_pushcfunction( L, nova_array_register );
629        lua_pushvalue( L, lua_upvalueindex( 1 ) );
630        lua_pushvalue( L, 1 );
631        lua_call( L, 2, 1 );
632
633        if (!lua_isnoneornil( L, lua_upvalueindex( 3 ) )) // constructor
634        {
635                lua_pushvalue( L, lua_upvalueindex( 3 ) ); // constructor
636                lua_pushvalue( L, 1 );
637                lua_call( L, 1, 0 );
638        }
639
640        return 1;
641}
642
643static int nova_create_array_constructor( lua_State * L )
644{
645        if ( lua_type( L, 1 ) == LUA_TSTRING )
646        {
647                lua_getglobal( L, lua_tostring( L, 1 ) );
648                lua_replace( L, 1 );
649        }
650        luaL_checktype( L, 1, LUA_TTABLE );
651        if ( lua_isnoneornil( L, 2 ) )
652        {
653                if ( lua_type( L, 2 ) != LUA_TBOOLEAN ) luaL_checktype( L, 2, LUA_TSTRING );
654        }
655        if ( !lua_isnoneornil( L, 3 ) ) luaL_checktype( L, 3, LUA_TFUNCTION );
656        lua_settop( L, 3 );
657        lua_pushcclosure(L, nova_create_array_constructor_closure, 3);
658        return 1;
659}
660
661static int nova_register_storage( lua_State * L )
662{
663        bool blueprint = false;
664        bool constr    = false;
665        luaL_checktype( L, 1, LUA_TSTRING );
666        if ( !lua_isnoneornil( L, 2 ) )
667        {
668                luaL_checktype( L, 2, LUA_TSTRING );
669                blueprint = true;
670        }
671        if ( !lua_isnoneornil( L, 3 ) )
672        {
673                luaL_checktype( L, 3, LUA_TFUNCTION );
674                constr = true;
675        }
676        lua_settop( L, 3 );
677
678        lua_pushglobaltable( L );
679        lua_pushvalue( L, 1 );
680        lua_rawget( L, -2 );
681
682        if ( !lua_isnil( L, -1 ) ) luaL_error( L, "lua.nova - storage \"%s\" already registered!", lua_tolstring( L, lua_upvalueindex(1), 0 ) );
683
684        lua_newtable( L ); // g t
685        lua_pushvalue( L, 1 ); // g t name
686        lua_pushvalue( L, -2 ); // g t name, duplicate table
687        lua_pushvalue( L, 1 ); // g t name, dt, name
688
689        lua_setfield( L, -2, "__name" );
690        if ( blueprint )
691        {
692                lua_pushvalue( L, 2 );
693                lua_setfield( L, -2, "__blueprint" );
694        }
695        lua_rawset( L, 4 );
696
697        lua_pushcfunction( L, nova_create_constructor );
698        lua_pushvalue( L, -2 ); // storage
699
700        if ( blueprint )
701                lua_pushvalue( L, 2 );
702        else
703                lua_pushnil( L );
704
705        if ( constr )
706                lua_pushvalue( L, 3 );
707        else
708                lua_pushnil( L );
709        lua_call( L, 3, 1 );
710        return 1;
711}
712
713static int nova_register_array_storage( lua_State * L )
714{
715        bool blueprint = false;
716        bool constr    = false;
717        luaL_checktype( L, 1, LUA_TSTRING );
718        if ( !lua_isnoneornil( L, 2 ) )
719        {
720                if ( lua_type( L, 2 ) != LUA_TBOOLEAN ) luaL_checktype( L, 2, LUA_TSTRING );
721                blueprint = true;
722        }
723        if ( !lua_isnoneornil( L, 3 ) )
724        {
725                luaL_checktype( L, 3, LUA_TFUNCTION );
726                constr = true;
727        }
728        lua_settop( L, 3 );
729        lua_pushglobaltable( L );
730
731        lua_pushvalue( L, 1 );
732        lua_rawget( L, -2 );
733        if ( !lua_isnil( L, -1 ) ) luaL_error( L, "storage \"%s\" already registered!", lua_tolstring( L, lua_upvalueindex(1), 0 ) );
734
735        lua_newtable( L );
736        lua_pushvalue( L, 1 ); // name
737        lua_pushvalue( L, -2 ); // duplicate table
738        lua_pushvalue( L, 1 ); // name
739        lua_setfield( L, -2, "__name" );
740        if ( blueprint )
741        {
742                lua_pushvalue( L, 2 );
743                lua_setfield( L, -2, "__blueprint" );
744        }
745        lua_rawset( L, 4 );
746
747        lua_pushcfunction( L, nova_create_array_constructor );
748        lua_pushvalue( L, -2 ); // storage
749
750        if ( blueprint )
751                lua_pushvalue( L, 2 );
752        else
753                lua_pushnil( L );
754
755        if ( constr )
756                lua_pushvalue( L, 3 );
757        else
758                lua_pushnil( L );
759
760        lua_call( L, 3, 1 );
761        return 1;
762}
763
764static const luaL_Reg nova_f[] = {
765        { "TFLAGS",                    nova_type_FLAGS },
766        { "TBLUEPRINT",                nova_type_BLUEPRINT },
767        { "TARRAY",                    nova_type_ARRAY },
768        { "TMAP",                      nova_type_MAP },
769        { "TID",                       nova_type_ID },
770        { "iif",                       nova_iif },
771        { "register",                  nova_register },
772        { "array_register",            nova_array_register },
773        { "declare",                   nova_declare },
774        { "create_seq_function",       nova_create_seq_function },
775        { "apply_blueprint",           nova_apply_blueprint },
776        { "apply_blueprint_values",    nova_apply_blueprint_values },
777        { "register_blueprint",        nova_register_blueprint },
778        { "create_constructor",        nova_create_constructor },
779        { "register_storage",          nova_register_storage },
780        { "register_array_storage",    nova_register_array_storage },
781        { "create_array_constructor",  nova_create_array_constructor },
782        {NULL, NULL}
783};
784
785
786int luaopen_nova( lua_State * L )
787{
788        lua_createtable( L, 0, 0 );
789        nlua_register( L, nova_f, -1 );
790        return 1;
791}
792
793void nv::lua::register_nova( state* a_state )
794{
795        lua_State* L = a_state->get_raw();
796        int stack = lua_gettop( L );
797
798        lua_pushlightuserdata( L, a_state );
799        lua_setfield( L, LUA_REGISTRYINDEX, NV_STATE );
800
801        lua_newtable( L );
802        lua_setfield( L, LUA_REGISTRYINDEX, NV_BLUEPRINTS );
803
804        luaL_requiref( L, "nova", luaopen_nova, 1 );
805        lua_settop( L, stack );
806}
Note: See TracBrowser for help on using the repository browser.