Overview
Comment: | continue iterating on object model |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
c0fd81ac3da7bd2f63aa6d05699bbac1 |
User & Date: | lexi on 2025-02-28 00:10:28 |
Other Links: | manifest | tags |
Context
2025-02-28
| ||
13:38 | update docs, add support for script method list Leaf check-in: e72ff06ec2 user: lexi tags: trunk | |
00:10 | continue iterating on object model check-in: c0fd81ac3d user: lexi tags: trunk | |
2025-02-21
| ||
22:02 | add janet API bootstrapping infra (prim, core), begin building executor (vm.c), design class model, continue working on loading, add script instances, tidy up src organization, build janet to use godot malloc/free check-in: 91e02e35d5 user: lexi tags: trunk | |
Changes
Modified lib/core.janet from [a791260fb2] to [4bd262c377].
20 20 (defn recurse [acc dox t & r] 21 21 (cond 22 22 (string? t) 23 23 (recurse acc [;dox t] ;r) 24 24 (or (struct? t) 25 25 (keyword? t)) 26 26 (recurse [;acc t] dox ;r) 27 - [[;(if (empty? dox) [] 27 + :else [[;(if (empty? dox) [] 28 28 [{:doc (string/join dox)}]) 29 29 ;acc] t ;r])) 30 30 (recurse [] [] ;args)) 31 31 32 32 (defmacro class [name & dfn] 33 33 (def def-map (tuple tuple (dyn *current-file*) 34 34 ;(tuple/sourcemap (dyn :macro-form)))) ................................................................................ 67 67 (def doc-str (string/join dox)) 68 68 (def body spec) 69 69 (with-dyns [*class-path* 70 70 [;(or (dyn *class-path*) []) name]] 71 71 (with-syms [$local-env $parent-env $form] 72 72 ~(let [,$parent-env (or @scope (curenv)) 73 73 ,$local-env (,table/setproto 74 - @{ '@name ,(mapped-val (keyword name)) 74 + @{ '@id ,(mapped-val (keyword name)) 75 75 '@gd-id ,(mapped-val (string export-name)) 76 76 '@inherit ,(mapped-val super) 77 77 '@mode ,(mapped-val mode) 78 78 '@doc ,(if (empty? dox) nil 79 79 (mapped-val doc-str))} 80 80 ,$parent-env) 81 81 ,name ,$local-env] ................................................................................ 92 92 (defn- member [& x] 93 93 (string/join [;(or (dyn *class-path*) []) 94 94 ;x] ".")) 95 95 96 96 (defmacro defclass* [id meta & r] 97 97 ~(def ,id ,;meta (class ,id ,;r))) 98 98 99 -(defmacro defclass [id & r] ~(defclass* ,id [] ,;r)) 100 -(defmacro defclass- [id & r] ~(defclass* ,id [:private] ,;r)) 99 +(defmacro defclass [id & r] ~(defclass* ,id [:subclass] ,;r)) 100 +(defmacro defclass- [id & r] ~(defclass* ,id [:subclass :private] ,;r)) 101 101 102 102 (defn- parse-sig [sig] 103 103 (match sig 104 104 ([ty id dox & r] (string? dox)) 105 105 [{:type (eval ty) :id id :doc dox} 106 106 ;(parse-sig r)] 107 - [ty id & r] [{:type (eval ty) :id id} 107 + [ty id & r] [{:type (eval ty) :id (tuple 'quote id)} 108 108 ;(parse-sig r) ] 109 109 _ [])) 110 110 111 111 (defmacro defm [id & rest] 112 - (def (meta ret sig & body) (assemble-meta rest)) 112 + (def (meta sig ret & body) (assemble-meta rest)) 113 113 (def args (parse-sig sig)) 114 - (def md [;meta :method {:sig args :ret (eval ret)}]) 115 - (def arg-names ['me ;(map (fn [{:id id}] id) args)]) 114 + (def md [;meta {:method {:sig args :ret (eval ret)}}]) 115 + (def arg-names ['me ;(map (fn [{:id (_ id)}] id) args)]) 116 116 (def path (symbol (member id))) 117 117 ~(def ,id ,;md (fn ,path ,arg-names ,;body))) 118 118 119 119 (defmacro defm- [id & r] ~(defm ,id :private ,;r)) 120 120 121 121 (defmacro prop [id & args] 122 122 (def (meta-list ty init-val)
Modified lib/prim.janet from [36c3aeafd8] to [81bf72f2dc].
1 1 # [ʞ] lib/prim.janet 2 2 # ~ lexi hale <lexi@hale.su> 3 3 # 🄯 AGPLv3 4 4 # ? declares the primitives supplied by gdjn 5 5 # > (import /lib/prim) 6 6 7 -(def *gd-api-map* @{}) 7 +(def *gd-api-ext* @{}) 8 8 9 9 (defmacro- extern [name] 10 10 (def sym (gensym)) 11 - (put *gd-api-map* sym name) 11 + (put *gd-api-ext* sym name) 12 12 ~(def ,name ',sym)) 13 13 14 14 # takes a string and returns a prim/class-handle 15 15 # for a native godot class 16 16 (extern class-load) 17 17 18 18 # an abstract that wraps a class and provides
Modified makefile from [3ece26026f] to [2e0c155ba6].
92 92 export gd_build_gen = $g 93 93 export gd_api_spec = $g/extension_api.json 94 94 export gd_api_iface = $g/gdextension_interface.h 95 95 96 96 .PHONY: all clean purge 97 97 all: $o/gdjn.so 98 98 clean: 99 - rm "$o/"*.o "$g/"*.{jimage,h} "$o/gdjn.so" 99 + rm "$o/"*.o "$g/"*.{jimage,h,json} "$o/gdjn.so" 100 100 purge: 101 101 rm "$o/"* "$g/"* 102 102 $(MAKE) -C "$(janet.src.path)" clean 103 103 104 104 %/:; $(path-ensure) 105 105 %: | $(@D)/ 106 106
Modified src/gdjn.h from [a8262d25e1] to [412845665b].
12 12 13 13 typedef void (*GDExtensionInterfacePrintError)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line, GDExtensionBool p_editor_notify); 14 14 15 15 #define _emit(fn, msg) \ 16 16 (gdjn_ctx -> gd.fn((msg), __func__, __FILE__, __LINE__, true)) 17 17 #define _warn(msg) _emit(warn, msg) 18 18 #define _err(msg) _emit(err, msg) 19 + 20 +#define _emitMsg(fn, desc, msg) \ 21 + (gdjn_ctx -> gd.fn((desc), (msg), __func__, __FILE__, __LINE__, true)) 22 +#define _errMsg(desc, msg) _emitMsg(errMsg, desc, msg) 23 + 19 24 20 25 typedef GDExtensionBool gdBool; 21 26 22 27 #define _alloc(ty, n) \ 23 28 ((typeof(ty)*)gdjn_alloc(sizeof(ty) * (n))) 24 29 #define _realloc(v, ty, n) \ 25 30 ((typeof(ty)*)gdjn_realloc((v), sizeof(ty) * (n)))
Modified src/janet-lang.gcd from [101fec1406] to [4162c1685e].
34 34 impl _can_inherit_from_file() -> bool { return true; }; 35 35 36 36 impl _handles_global_class_type(string t) -> bool { return false; }; 37 37 impl _get_type() -> string { 38 38 gd_string s = {}; 39 39 _t(string).newWithUtf8Chars(&s, "JanetScriptText"); 40 40 return s; 41 + }; 42 + impl _get_public_functions() -> array[dictionary] { 43 + gd_array list; 44 + _t(array).empty(&list, nullptr); 45 + return list; 46 + }; 47 + impl _get_public_constants() -> dictionary { 48 + gd_dictionary consts; 49 + _t(dictionary).empty(&consts, nullptr); 50 + return consts; 51 + }; 52 + impl _get_public_annotations() -> array[dictionary] { 53 + gd_array list; 54 + _t(array).empty(&list, nullptr); 55 + return list; 41 56 }; 42 57 impl _get_recognized_extensions() -> packed-string-array { 43 58 gd_packedStringArray r = {}; 44 59 _t(packedStringArray).empty(&r, nullptr); 45 60 _gdu_array_string_pushLit(&r, "janet"); 46 61 _gdu_array_string_pushLit(&r, "jimage"); 47 62 return r; ................................................................................ 183 198 return dict; 184 199 }; 185 200 }; 186 201 187 202 class JanetScript is ScriptExtension { 188 203 var as string: path; 189 204 var JanetTable*: env; 205 + var pstr: id; 206 + var pstr: exportID; 207 + var pstr: uid; 208 + var pstr: doc; 209 + var pstr: inherit; 190 210 211 + var as array[dictionary]: methodBinds; 212 + 213 + use "vm.h"; 214 + 191 215 new { 192 216 _t(string).empty(&me -> path, nullptr); 193 217 me -> env = nullptr; 218 + 219 + _t(array).empty(&me -> methodBinds, nullptr); 220 + me -> id = (pstr){}; 221 + me -> exportID = (pstr){}; 222 + me -> uid = (pstr){}; 223 + me -> doc = (pstr){}; 224 + me -> inherit = (pstr){}; 194 225 }; 195 226 del { 196 227 _t(string).dtor(&me -> path); 228 + _t(array).dtor(&me -> methodBinds); 197 229 if (me -> env) janet_gcunroot(janet_wrap_table(me -> env)); 230 + _drop(me -> id); 231 + _drop(me -> exportID); 232 + _drop(me -> uid); 233 + _drop(me -> doc); 234 + _drop(me -> inherit); 235 + 198 236 }; 199 237 200 238 class BaseInstance is Object { 201 239 var as ref JanetScript: script; 202 240 del { 203 241 gd_refCounted_unreference(me -> script); 204 242 printf("del script instance\n"); ................................................................................ 239 277 impl _get_base_script() -> ref Script { 240 278 return nullptr; 241 279 }; 242 280 impl _has_static_method(string-name method) -> bool { 243 281 return false; 244 282 }; 245 283 impl _is_tool() -> bool { return false; }; (* FIXME *) 246 - impl _get_global_name(string-name id) -> string-name { 284 + impl _get_global_name() -> string-name { 285 + if (me -> exportID.v) 286 + return gdu_internp(me -> exportID); 247 287 return gdu_sym_null(); 248 288 }; 249 289 impl _is_abstract() -> bool { 250 290 return false; (* TODO abuse for non-class scripts? *) 251 291 }; 252 292 impl _get_instance_base_type() -> string-name { 253 - return _gdu_intern("ScriptExtension"); 293 + return gdu_internp(me -> inherit); 254 294 }; 255 295 impl _is_valid() -> bool { 256 296 return true; 257 297 }; 258 298 impl _get_documentation() -> array[dictionary] { 259 299 gd_array dox; 260 300 _t(array).empty(&dox, nullptr); 261 301 auto empty = gdu_sym_null(); 262 302 _t(array).setTyped(&dox, 263 303 GDEXTENSION_VARIANT_TYPE_DICTIONARY, &empty, &empty); 264 304 _t(stringName).dtor(&empty); 265 305 return dox; 266 306 }; 307 + 308 + use { 309 + static pstr 310 + classParam 311 + ( JanetTable* env, 312 + const char* sym, 313 + pstr dflt 314 + ) { 315 + Janet v = janet_table_rawget(env, janet_csymbolv(sym)); 316 + if (janet_type(v) != JANET_TABLE) return dflt; 317 + 318 + Janet s = janet_table_rawget(janet_unwrap_table(v), 319 + janet_ckeywordv("value")); 320 + if (janet_type(s) == JANET_NIL) return dflt; 321 + 322 + JanetString str = janet_unwrap_string(s); 323 + return (pstr) { 324 + .v = (char*)str, 325 + .sz = janet_string_length(str), 326 + }; 327 + } 328 + }; 329 + impl _reload(bool keepState) -> int { 330 + gd_array_clear(&me -> methodBinds); 331 + /* parse the class environment */ 332 + JanetTable* const env = me -> env; 333 + printf("core reload\n"); 334 + 335 + pstr id = classParam(env, "@id", (pstr){}); 336 + pstr gdid = classParam(env, "@gd-id", (pstr){}); 337 + pstr inherit = classParam(env, "@inherit", _pstrLit("RefCounted")); 338 + pstr doc = classParam(env, "@doc", (pstr){}); 339 + 340 + if (gdid.v) me -> exportID = pstrDup(gdid); 341 + else me -> exportID = pstrDup(id); 342 + if (id.v) me -> id = pstrDup(id); 343 + 344 + if (doc.v) me -> doc = pstrDup(doc); 345 + if (inherit.v) me -> inherit = pstrDup(inherit); 346 + 347 + Janet wenv = janet_wrap_table(env); 348 + /* scan for bindings */ 349 + for (Janet key = janet_next(wenv, janet_wrap_nil()); 350 + janet_type(key) != JANET_NIL; 351 + key = janet_next(wenv, key)) { 352 + 353 + Janet val = janet_table_rawget(env, key); 354 + 355 + if (!janet_checktypes(key, JANET_TFLAG_BYTES)) continue; 356 + printf(" * consider val id %s (%s)\n", 357 + janet_unwrap_string(key), 358 + janet_type_names[janet_type(val)]); 359 + if (!janet_checktypes(val, JANET_TFLAG_DICTIONARY)) continue; 360 + JanetTable* v = janet_unwrap_table(val); 361 + Janet ty; 362 + const bool priv = gdjn_vm_metaFlag(v, "private"); 363 + JanetString jkey = janet_unwrap_string(key); 364 + 365 + if (gdjn_vm_metaKey(v, "method", &ty)) { 366 + /* && janet_type(ty) == JANET_TABLE) { */ 367 + printf(" * is method %s\n", 368 + janet_type_names[janet_type(ty)]); 369 + JanetTable* tspec = janet_unwrap_table(ty); 370 + /* janet_unwrap_function() */ 371 + gd_dictionary meta; 372 + _t(dictionary).empty(&meta, nullptr); 373 + gdu_setKey_str(&meta, _pstrLit("name"), 374 + (pstr) { 375 + .sz = janet_string_length(jkey), 376 + .v = (char*)jkey, 377 + }); 378 + 379 + /* build arg array */ 380 + gd_array argList; 381 + _t(array).empty(&argList, nullptr); 382 + for (size_t j = 0; j < tspec -> count; ++j) { 383 + /* 384 + gd_dictionary 385 + gdu_array_append(&argList_, ) 386 + */ 387 + } 388 + 389 + {gd_variant tv = gd_variant_of_array(argList); 390 + gdu_setKey(&meta, _pstrLit("args"), &tv);} 391 + 392 + 393 + {gd_variant tv = gd_variant_of_dictionary(meta); 394 + gd_array_append(&me -> methodBinds, &tv);} 395 + 396 + _t(array).dtor(&argList); 397 + _t(dictionary).dtor(&meta); 398 + } else if (gdjn_vm_metaKey(v, "prop", &ty)) { 399 + } else if (gdjn_vm_metaKey(v, "const", &ty)) { 400 + } else if (gdjn_vm_metaFlag(v, "subclass")) { 401 + }; 402 + /* else: the value is not meaningful to godot; skip over */ 403 + } 404 + return gd_Error_ok; 405 + }; 267 406 268 407 (* 269 408 impl _update_exports() { 270 409 271 410 }; 272 411 impl _placeholder_instance_create 273 412 (ref Object forObj) -> ref Object { ................................................................................ 322 461 if (e == 0) { 323 462 me -> super.env = cls; 324 463 } else { 325 464 _err("janet module could not be loaded"); 326 465 errorCode = gd_Error_errParseError; 327 466 janet_gcunroot(janet_wrap_table(cls)); 328 467 } 468 + if (errorCode != gd_Error_ok) return errorCode; 329 469 330 - return errorCode; 470 + /* invoke super by static dispatch */ 471 + return gdjn_class_JanetScript_method__reload(&me -> super, keepState); 331 472 }; 332 473 }; 333 474 334 475 import { 335 476 typedef struct gdjn_janet_image { 336 477 size_t sz; 337 478 uint8_t* buf;
Modified src/type.h from [7c7116050b] to [91836a2225].
19 19 #define _pstrOf(a) ((pstr){.v=_strDynMem(a), .sz=_strDynSz(a)}) 20 20 21 21 #define _array(t) struct {t* v; size_t sz;} 22 22 typedef _array(char) pstr; 23 23 24 24 #define _pstrLit(a) ((pstr){.v=(a),.sz=sizeof(a)-1}) 25 25 26 -#define _drop(x) ({ \ 26 +#define _drop(x) { \ 27 27 if (x.v) { \ 28 28 _free (x.v); \ 29 29 x.v = nullptr; \ 30 30 x.sz = 0; \ 31 31 } \ 32 -}) 32 +} 33 33 #define _new(T, n) ((T){ \ 34 - .v = _alloc( typeof( ((typeof(T)) {}).v ), n), \ 34 + .v = _alloc( typeof( *((typeof(T)) {}).v ), n), \ 35 35 .sz = n, \ 36 36 }) 37 37 38 +static inline pstr 39 +pstrDup(pstr p) { 40 + if (p.v == nullptr) return p; 41 + if (p.sz == 0) p.sz = strlen(p.v); 42 + auto n = _new(pstr, p.sz + 1); 43 + memcpy(n.v, p.v, p.sz); 44 + n.v[p.sz] = 0; 45 + n.sz = p.sz; 46 + return n; 47 +}
Modified src/util-gd.h from [79dbc22466] to [bf54805293].
33 33 return r; 34 34 } 35 35 36 36 static inline gd_stringName 37 37 gdu_intern (const char* str) { 38 38 return gdu_intern_sz(str, 0); 39 39 } 40 + 41 +static inline gd_stringName 42 +gdu_internp (pstr p) { 43 + return gdu_intern_sz(p.v, p.sz); 44 +} 40 45 41 46 static inline gd_stringName 42 47 gdu_sym_null(void) { 43 48 gd_stringName n; 44 49 _t(stringName).empty(&n, nullptr); 45 50 return n; 46 51 } ................................................................................ 55 60 static inline gd_string 56 61 gdu_str_sz (const char* str, const size_t sz) { 57 62 gd_string r = {}; 58 63 if (sz == 0) _t(string).newWithUtf8Chars(&r, str); 59 64 else _t(string).newWithUtf8CharsAndLen(&r, str, sz); 60 65 return r; 61 66 } 67 + 68 +static inline gd_string 69 +gdu_pstr (pstr p) { 70 + return gdu_str_sz(p.v, p.sz); 71 +} 62 72 63 73 static inline gd_string 64 74 gdu_str (const char* str) { 65 75 return gdu_str_sz(str, 0); 66 76 } 67 77 68 78 #define _gdu_intern(x) (gdu_intern_sz((x), sizeof(x)-1)) ................................................................................ 368 378 gd_variant v = gd_variant_of_dictionary(*dict); 369 379 _withSym(keyName, key, { 370 380 uint8_t ok = false; 371 381 _t(variant).setNamed(&v, &keyName, val, &ok); 372 382 }); 373 383 } 374 384 385 +static inline void 386 +gdu_setKey_str 387 +( gd_dictionary* const dict, 388 + pstr const key, 389 + pstr const val 390 +) { 391 + gd_string s = gdu_str_sz(val.v, val.sz); 392 + gd_variant v = gd_variant_of_string(s); 393 + gdu_setKey(dict, key, &v); 394 + _t(string).dtor(&s); 395 +}
Modified src/vm.c from [57a8603486] to [8b30a5746f].
315 315 _err("no init fn in api envtbl"); 316 316 goto fail; 317 317 } 318 318 auto initFn = janet_unwrap_function( 319 319 janet_table_get(janet_unwrap_table(initDef), 320 320 janet_ckeywordv("value"))); 321 321 Janet ret; 322 - auto e = janet_pcall(initFn, 0, nullptr, &ret, nullptr); 322 + auto e = janet_pcall(initFn, 1, 323 + (Janet[]) {janet_wrap_table(tgt)}, 324 + &ret, nullptr); 323 325 if (e == JANET_SIGNAL_ERROR) { 324 - _err("failed to unpack the janet environment"); 326 + _errMsg("failed to unpack the janet environment", 327 + (char*)janet_unwrap_string(ret)); 325 328 goto fail; 326 329 } 330 + /* janet_table_merge_table(tgt, janet_unwrap_table(ret)); */ 327 331 printf("environment load complete\n"); 328 332 fail: 329 333 janet_gcunlock(gc); 330 334 /* janet_collect(); */ 331 335 } 332 336 333 337 JanetTable* gdjn_vm_api_build_compTime(void) {
Modified tool/api-compile.janet from [56067a22ef] to [ad62ccc075].
41 41 # in turn. the array *gd-api-map* is assembled at 42 42 # compile-time and then used by the init function at 43 43 # runtime to enumerate and install the core modules. 44 44 # when core modules use a primitive, they declare their 45 45 # own *gd-api-map* which maps gensyms to the name of 46 46 # the desired primitive. 47 47 (def *gd-api-map* @{}) 48 -(defn- install [name env] 48 +(defn- dict-filter [pred dict] 49 + (def d @{}) 50 + (loop [[k v] :pairs dict] 51 + (when (pred k v) 52 + (put d k v))) 53 + d) 54 +(defn- install [name env-raw] 55 + (def env (dict-filter 56 + |(and (table? $1) 57 + (not ($1 :private))) 58 + env-raw)) 49 59 (put *gd-api-map* name env) 50 - (when (has-key? env '*gd-api-map*) 51 - (def gdmap (get-in env ['*gd-api-map* :value])) 60 + (when-let [b (get env '*gd-api-ext*) 61 + ok (table? b)] 62 + (def gdmap (get-in env ['*gd-api-ext* :value])) 52 63 (loop [[val key] :pairs gdmap 53 64 :when (safe-to-export? val)] 54 65 (def sym (symbol '-val- (bxor (hash name) (hash val)))) 55 66 (put marshal-map val sym) 56 67 (put unmarshal-map sym val)) 57 68 (merge-into extern-table gdmap))) 58 69 ................................................................................ 69 80 # macro implementations can be provided directly in janet 70 81 # and incorporated into the API image without having to 71 82 # implement anything beyond the primitive API in C 72 83 73 84 # this function is exported as part of api.jimage. 74 85 # it will be called from vm.c after initializing 75 86 # the primitive bindings 76 -(defn init [] 87 +(defn init [core-env] 77 88 (print "beginning merge") 78 89 (merge-into module/cache *gd-api-map*) 90 + (print "loaded modules, forcing imports") 91 + (merge-into core-env (get *gd-api-map* "core")) 79 92 (print "api loaded")) 80 93 81 94 # this is the build-time entry point, which does 82 95 # the work of assembling the modules and marshalling 83 96 # them out. it is not exported 84 97 (defn main [_ out-path] 85 98 (def env @{}) 86 99 (each sym '[init marshal-map unmarshal-map] 87 100 (put env sym ((curenv) sym))) 88 101 (let [blob (marshal env extern-table)] 89 102 (with [fd (file/open out-path :w)] 90 103 (:write fd blob))) 91 104 0)
Modified tool/c-bind-gen.janet from [37b502b2c6] to [2a6ade94f8].
146 146 has is-empty find rfind count 147 147 reverse slice duplicate] 148 148 :ctors {:empty []} 149 149 } 150 150 packed-types) 151 151 {:id array :mode :dc 152 152 :binds [ref set-typed operator-index operator-index-const] 153 - :methods [size is-empty clear] 153 + :methods [size is-empty clear append append-array insert] 154 154 :ctors {:empty []} 155 155 :indexed true} 156 156 {:id dictionary :mode :dc 157 157 :binds [set-typed operator-index operator-index-const] 158 158 :methods [size is-empty clear] 159 159 :ctors {:empty []} 160 160 :indexed true}
Modified tool/class-compile.janet from [22543b9ce7] to [495ac069e8].
1008 1008 (let [uf (unit-files unit)] 1009 1009 (:write stdout (case emit 1010 1010 "header" (lines->str (uf :header)) 1011 1011 "loader" (lines->str (uf :impl)) 1012 1012 (error :bad-cmd))))) 1013 1013 1014 1014 (defn main [& argv] 1015 - (entry ;argv)) 1016 - # (try (entry ;argv) 1017 - # ([e] (:write stderr (style ;(err->msg e)) "\n")))) 1015 + # (entry ;argv)) 1016 + (try (entry ;argv) 1017 + ([e] (:write stderr (style ;(err->msg e)) "\n"))))