33aa1e406cdc — Leonard Ritter 7 days ago
* initial support for inspecting compiled functions, blocks and calls
M include/scopes/scopes.h +22 -0
@@ 56,6 56,7 @@ namespace scopes {
     struct Frame;
     struct Value;
     struct Closure;
+    struct Block;
 }
 
 extern "C" {

          
@@ 73,6 74,8 @@ typedef scopes::Closure sc_closure_t;
 
 typedef scopes::ValueRef sc_valueref_t;
 
+typedef scopes::Block sc_block_t;
+
 // some of the return types are technically illegal in C, but we take care
 // that the alignment is correct
 #pragma GCC diagnostic ignored "-Wreturn-type-c-linkage"

          
@@ 92,6 95,8 @@ typedef struct sc_closure_ sc_closure_t;
 
 typedef struct sc_valueref_ { sc_value_t *_0; const sc_anchor_t *_1; } sc_valueref_t;
 
+typedef struct sc_block_ sc_block_t;
+
 #endif
 
 // aliasing uint64_t to a struct with a single uint64_t member is UB, and hasn't

          
@@ 534,6 539,23 @@ SCOPES_LIBEXPORT const sc_type_t *sc_ima
 
 SCOPES_LIBEXPORT const sc_type_t *sc_sampled_image_type(const sc_type_t *_type);
 
+// inspect API
+
+// Function
+SCOPES_LIBEXPORT sc_block_t *sc_function_get_body(sc_valueref_t fn);
+
+// Block
+SCOPES_LIBEXPORT int sc_block_instruction_count(sc_block_t *block);
+SCOPES_LIBEXPORT sc_valueref_t sc_block_get_instruction(sc_block_t *block, int index);
+SCOPES_LIBEXPORT sc_valueref_t sc_block_terminator(sc_block_t *block);
+
+// Call
+SCOPES_LIBEXPORT sc_valueref_t sc_icall_callee(sc_valueref_t value);
+SCOPES_LIBEXPORT int sc_icall_argcount(sc_valueref_t value);
+SCOPES_LIBEXPORT sc_valueref_t sc_icall_getarg(sc_valueref_t value, int index);
+SCOPES_LIBEXPORT sc_block_t *sc_icall_exception_body(sc_valueref_t value);
+SCOPES_LIBEXPORT sc_type_raises_t sc_icall_exception_type(sc_valueref_t value);
+
 #if defined __cplusplus
 }
 #endif

          
M lib/scopes/inspect.sc +28 -0
@@ 1,7 1,35 @@ 
 
+inline block-generator (self)
+    count := sc_block_instruction_count self
+    Generator
+        inline () 0
+        inline (i) (i < count)
+        inline (i) (sc_block_get_instruction self i)
+        inline (i) (+ i 1)
+
+type+ SCILBlock
+    inline __imply (cls T)
+        static-if (T == Generator) block-generator
+
+    __countof := sc_block_instruction_count
+    terminator := sc_block_terminator
 
+type+ Value
+    inline icall-args (self)
+        count := sc_icall_argcount self
+        Generator
+            inline () 0
+            inline (i) (i < count)
+            inline (i) (sc_icall_getarg self i)
+            inline (i) (+ i 1)
 
+    function-get-body := sc_function_get_body
 
+    icall-callee := sc_icall_callee
+    icall-argcount := sc_icall_argcount
+    icall-getarg := sc_icall_getarg
+    icall-exception-body := sc_icall_exception_body
+    icall-exception-type := sc_icall_exception_type
 
 do
     locals;

          
M src/error.hpp +2 -0
@@ 497,6 497,8 @@ formatters:
     T(RTTypeBitcountMismatch, \
         "runtime: provided word count (%1) does not match word count of type %0 (%2)", \
         PType, int, int) \
+    T(RTUndefinedAttribute, \
+        "runtime: undefined attribute") \
 
 // main
 #define SCOPES_MAIN_ERROR_KIND() \

          
M src/globals.cpp +73 -0
@@ 2400,6 2400,67 @@ const sc_type_t *sc_sampled_image_type(c
     return sampled_image_type(cast<ImageType>(_type));
 }
 
+// Inspect API
+////////////////////////////////////////////////////////////////////////////////
+
+// Function
+////////////////////////////////////////////////////////////////////////////////
+
+sc_block_t *sc_function_get_body(sc_valueref_t fn) {
+    using namespace scopes;
+    return &fn.cast<Function>()->body;
+}
+
+// Block
+////////////////////////////////////////////////////////////////////////////////
+
+int sc_block_instruction_count(sc_block_t *block) {
+    assert(block);
+    return block->body.size();
+}
+
+sc_valueref_t sc_block_get_instruction(sc_block_t *block, int index) {
+    assert(block);
+    return block->body[index];
+}
+
+sc_valueref_t sc_block_terminator(sc_block_t *block) {
+    assert(block);
+    return block->terminator;
+}
+
+// Call
+////////////////////////////////////////////////////////////////////////////////
+
+sc_valueref_t sc_icall_callee(sc_valueref_t value) {
+    using namespace scopes;
+    return value.cast<Call>()->callee;
+}
+
+int sc_icall_argcount(sc_valueref_t value) {
+    using namespace scopes;
+    return value.cast<Call>()->args.size();
+}
+
+sc_valueref_t sc_icall_getarg(sc_valueref_t value, int index) {
+    using namespace scopes;
+    return value.cast<Call>()->args[index];
+}
+
+sc_block_t *sc_icall_exception_body(sc_valueref_t value) {
+    using namespace scopes;
+    return &value.cast<Call>()->except_body;
+}
+
+sc_type_raises_t sc_icall_exception_type(sc_valueref_t value) {
+    using namespace scopes;
+    SCOPES_RESULT_TYPE(const Type *);
+    auto exc = value.cast<Call>()->except;
+    if (!exc) {
+        SCOPES_C_ERROR(RTUndefinedAttribute);
+    }
+    SCOPES_C_RETURN(exc->get_type());
+}
 
 } // extern "C"
 

          
@@ 2752,6 2813,18 @@ void init_globals(int argc, char *argv[]
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_parse_from_path, TYPE_ValueRef, TYPE_String);
     DEFINE_RAISING_EXTERN_C_FUNCTION(sc_parse_from_string, TYPE_ValueRef, TYPE_String);
 
+    DEFINE_EXTERN_C_FUNCTION(sc_function_get_body, TYPE_Block, TYPE_ValueRef);
+
+    DEFINE_EXTERN_C_FUNCTION(sc_block_instruction_count, TYPE_I32, TYPE_Block);
+    DEFINE_EXTERN_C_FUNCTION(sc_block_get_instruction, TYPE_ValueRef, TYPE_Block, TYPE_I32);
+    DEFINE_EXTERN_C_FUNCTION(sc_block_terminator, TYPE_ValueRef, TYPE_Block);
+
+    DEFINE_EXTERN_C_FUNCTION(sc_icall_callee, TYPE_ValueRef, TYPE_ValueRef);
+    DEFINE_EXTERN_C_FUNCTION(sc_icall_argcount, TYPE_I32, TYPE_ValueRef);
+    DEFINE_EXTERN_C_FUNCTION(sc_icall_getarg, TYPE_ValueRef, TYPE_ValueRef, TYPE_I32);
+    DEFINE_EXTERN_C_FUNCTION(sc_icall_exception_body, TYPE_Block, TYPE_ValueRef);
+    DEFINE_RAISING_EXTERN_C_FUNCTION(sc_icall_exception_type, TYPE_Type, TYPE_ValueRef);
+
 #undef DEFINE_EXTERN_C_FUNCTION
 
 #ifdef SCOPES_WIN32

          
M src/type.cpp +2 -0
@@ 569,6 569,8 @@ void init_types() {
 
     DEFINE_OPAQUE_HANDLE_TYPE("Anchor", Anchor, TYPE_Anchor, nullptr);
 
+    DEFINE_OPAQUE_HANDLE_TYPE("SCILBlock", Block, TYPE_Block, nullptr);
+
 
     DEFINE_BASIC_TYPE("Value", ValueRef, TYPE_ValueRef, nullptr,
         tuple_type({ TYPE__Value, TYPE_Anchor }).assert_ok());

          
M src/type.hpp +3 -0
@@ 155,6 155,9 @@ typedef std::vector<const Type *> Types;
     \
     T(TYPE_Sampler, "Sampler") \
     \
+    /* inspect API */ \
+    T(TYPE_Block, "SCILBlock") \
+    \
     /* supertypes */ \
     T(TYPE_Immutable, "immutable") \
     T(TYPE_Aggregate, "aggregate") \

          
M testing/test_inspect.sc +18 -2
@@ 6,15 6,31 @@ import inspect
 # test introspection
 
 fn somefunc (a b)
+    print "somefunc called"
     if a
         return 1
     else
         return b
 
 somefunc := `[(static-typify somefunc bool i32)]
-
 assert ((tostring ('kind somefunc)) == "Function")
-
 assert ((tostring ('kind i32)) == "IntegerType")
 
+block := 'function-get-body somefunc
+
+for instr in block
+    print ('kind instr)
+    switch ('kind instr)
+    case ValueKind.Call
+        print "   " ('icall-callee instr)
+        for arg in ('icall-args instr)
+            print "   " arg
+        print (countof ('icall-exception-body instr))
+        try
+            print ('icall-exception-type instr)
+        except (e)
+            print "no exception type"
+    default;
+print ('kind ('terminator block))
+
 ;
  No newline at end of file