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

Last change on this file since 534 was 534, checked in by epyon, 8 years ago

CONTINUED:

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