2022-10-28 04:59:24 +01:00
//! Hacky comptime interpreter, courtesy of midnight code run fuelled by spite;
//! hope that one day this can use async... <33
// TODO: DODify
const std = @import ( " std " ) ;
2022-12-27 01:46:57 +00:00
const builtin = @import ( " builtin " ) ;
2022-10-28 04:59:24 +01:00
const ast = @import ( " ast.zig " ) ;
const zig = std . zig ;
const Ast = zig . Ast ;
const analysis = @import ( " analysis.zig " ) ;
2023-01-04 10:11:48 +00:00
const offsets = @import ( " offsets.zig " ) ;
2022-10-28 04:59:24 +01:00
const DocumentStore = @import ( " DocumentStore.zig " ) ;
2022-12-01 23:08:45 +00:00
pub const InternPool = @import ( " InternPool.zig " ) ;
pub const IPIndex = InternPool . Index ;
pub const IPKey = InternPool . Key ;
pub const ComptimeInterpreter = @This ( ) ;
2022-10-28 04:59:24 +01:00
2022-11-10 04:46:23 +00:00
const log = std . log . scoped ( . comptime_interpreter ) ;
2022-10-28 04:59:24 +01:00
allocator : std . mem . Allocator ,
2022-12-01 23:08:45 +00:00
ip : InternPool = . { } ,
2022-10-29 06:46:22 +01:00
document_store : * DocumentStore ,
2022-11-11 01:51:02 +00:00
uri : DocumentStore . Uri ,
2023-01-04 10:11:48 +00:00
decls : std . ArrayListUnmanaged ( Decl ) = . { } ,
namespaces : std . MultiArrayList ( Namespace ) = . { } ,
2022-10-28 04:59:24 +01:00
2022-10-30 08:07:49 +00:00
/// Interpreter diagnostic errors
errors : std . AutoArrayHashMapUnmanaged ( Ast . Node . Index , InterpreterError ) = . { } ,
2022-11-11 01:51:02 +00:00
pub fn getHandle ( interpreter : * ComptimeInterpreter ) * const DocumentStore . Handle {
// This interpreter is loaded from a known-valid handle so a valid handle must exist
return interpreter . document_store . getOrLoadHandle ( interpreter . uri ) . ? ;
}
2022-10-30 08:07:49 +00:00
pub const InterpreterError = struct {
code : [ ] const u8 ,
message : [ ] const u8 ,
} ;
2022-10-31 20:00:02 +00:00
/// `message` must be allocated with interpreter allocator
2022-10-31 05:51:51 +00:00
pub fn recordError ( interpreter : * ComptimeInterpreter , node_idx : Ast . Node . Index , code : [ ] const u8 , message : [ ] const u8 ) error { OutOfMemory } ! void {
2022-10-30 08:07:49 +00:00
try interpreter . errors . put ( interpreter . allocator , node_idx , . {
. code = code ,
. message = message ,
} ) ;
}
2022-10-28 04:59:24 +01:00
pub fn deinit ( interpreter : * ComptimeInterpreter ) void {
2022-10-31 20:00:02 +00:00
var err_it = interpreter . errors . iterator ( ) ;
while ( err_it . next ( ) ) | entry | interpreter . allocator . free ( entry . value_ptr . message ) ;
interpreter . errors . deinit ( interpreter . allocator ) ;
2022-12-01 23:08:45 +00:00
interpreter . ip . deinit ( interpreter . allocator ) ;
2022-12-27 01:46:57 +00:00
var i : usize = 0 ;
2023-01-04 10:11:48 +00:00
while ( i < interpreter . namespaces . len ) : ( i + = 1 ) {
interpreter . namespaces . items ( . decls ) [ i ] . deinit ( interpreter . allocator ) ;
interpreter . namespaces . items ( . usingnamespaces ) [ i ] . deinit ( interpreter . allocator ) ;
2022-12-27 01:46:57 +00:00
}
2023-01-04 10:11:48 +00:00
interpreter . namespaces . deinit ( interpreter . allocator ) ;
interpreter . decls . deinit ( interpreter . allocator ) ;
2022-10-28 04:59:24 +01:00
}
pub const Type = struct {
2022-11-01 03:36:13 +00:00
interpreter : * ComptimeInterpreter ,
2022-10-29 22:28:44 +01:00
2022-10-28 04:59:24 +01:00
node_idx : Ast . Node . Index ,
2022-12-01 23:08:45 +00:00
ty : IPIndex ,
2022-10-28 04:59:24 +01:00
} ;
pub const Value = struct {
2022-11-01 03:36:13 +00:00
interpreter : * ComptimeInterpreter ,
2022-10-29 22:28:44 +01:00
2022-10-28 04:59:24 +01:00
node_idx : Ast . Node . Index ,
2022-12-01 23:08:45 +00:00
ty : IPIndex ,
val : IPIndex ,
2022-10-28 04:59:24 +01:00
} ;
2023-01-04 10:11:48 +00:00
pub const Decl = struct {
name : [ ] const u8 ,
ty : IPIndex ,
val : IPIndex ,
alignment : u16 ,
address_space : std . builtin . AddressSpace ,
is_pub : bool ,
is_exported : bool ,
} ;
2023-01-14 13:07:52 +00:00
// pub const Comptimeness = enum { @"comptime", runtime };
2023-01-04 10:11:48 +00:00
pub const NamespaceIndex = InternPool . NamespaceIndex ;
pub const Namespace = struct {
/// always points to Namespace or Index.none
parent : NamespaceIndex ,
2023-01-14 13:07:52 +00:00
node_idx : Ast . Node . Index ,
/// Will be a struct, enum, union, opaque or .none
ty : IPIndex ,
2023-01-04 10:11:48 +00:00
decls : std . StringArrayHashMapUnmanaged ( Decl ) = . { } ,
usingnamespaces : std . ArrayListUnmanaged ( NamespaceIndex ) = . { } ,
2022-10-28 04:59:24 +01:00
2022-10-31 20:00:02 +00:00
// TODO: Actually use this value
// comptimeness: Comptimeness,
2023-01-14 13:07:52 +00:00
pub fn getLabel ( self : Namespace , tree : Ast ) ? Ast . TokenIndex {
2022-10-28 04:59:24 +01:00
const token_tags = tree . tokens . items ( . tag ) ;
2023-01-14 13:07:52 +00:00
switch ( tree . nodes . items ( . tag ) [ self . node_idx ] ) {
. block_two ,
. block_two_semicolon ,
. block ,
. block_semicolon ,
= > {
const lbrace = tree . nodes . items ( . main_token ) [ self . node_idx ] ;
if ( token_tags [ lbrace - 1 ] = = . colon and token_tags [ lbrace - 2 ] = = . identifier ) {
return lbrace - 2 ;
}
return null ;
2022-10-28 04:59:24 +01:00
} ,
2023-01-14 13:07:52 +00:00
else = > return null ,
}
2022-10-28 04:59:24 +01:00
}
} ;
pub const InterpretResult = union ( enum ) {
@ " break " : ? [ ] const u8 ,
break_with_value : struct {
label : ? [ ] const u8 ,
value : Value ,
} ,
value : Value ,
@ " return " ,
return_with_value : Value ,
nothing ,
pub fn maybeGetValue ( result : InterpretResult ) ? Value {
return switch ( result ) {
. break_with_value = > | v | v . value ,
. value = > | v | v ,
2022-10-28 19:24:38 +01:00
. return_with_value = > | v | v ,
2022-10-28 04:59:24 +01:00
else = > null ,
} ;
}
2022-10-28 06:22:03 +01:00
pub fn getValue ( result : InterpretResult ) error { ExpectedValue } ! Value {
return result . maybeGetValue ( ) orelse error . ExpectedValue ;
2022-10-28 04:59:24 +01:00
}
} ;
2022-10-29 22:28:44 +01:00
pub fn huntItDown (
interpreter : * ComptimeInterpreter ,
2023-01-04 10:11:48 +00:00
namespace : NamespaceIndex ,
2022-10-29 22:28:44 +01:00
decl_name : [ ] const u8 ,
options : InterpretOptions ,
2023-01-14 20:49:27 +00:00
) error { IdentifierNotFound } ! Decl {
2022-12-27 01:46:57 +00:00
_ = options ;
var current_namespace = namespace ;
2023-01-04 10:11:48 +00:00
while ( current_namespace ! = . none ) {
const decls : std . StringArrayHashMapUnmanaged ( Decl ) = interpreter . namespaces . items ( . decls ) [ @enumToInt ( current_namespace ) ] ;
defer current_namespace = interpreter . namespaces . items ( . parent ) [ @enumToInt ( current_namespace ) ] ;
if ( decls . get ( decl_name ) ) | decl | {
return decl ;
2022-10-29 22:28:44 +01:00
}
}
return error . IdentifierNotFound ;
}
2022-10-28 04:59:24 +01:00
// Might be useful in the future
pub const InterpretOptions = struct { } ;
2022-10-28 06:22:03 +01:00
pub const InterpretError = std . mem . Allocator . Error | | std . fmt . ParseIntError | | std . fmt . ParseFloatError | | error {
InvalidCharacter ,
InvalidBase ,
ExpectedValue ,
InvalidOperation ,
CriticalAstFailure ,
InvalidBuiltin ,
2022-10-28 19:24:38 +01:00
IdentifierNotFound ,
2022-10-29 22:28:44 +01:00
MissingArguments ,
ImportFailure ,
2022-10-31 05:51:51 +00:00
InvalidCast ,
2022-10-28 06:22:03 +01:00
} ;
2022-12-27 01:46:57 +00:00
2022-10-28 04:59:24 +01:00
pub fn interpret (
interpreter : * ComptimeInterpreter ,
node_idx : Ast . Node . Index ,
2023-01-14 13:07:52 +00:00
namespace : NamespaceIndex ,
2022-10-28 04:59:24 +01:00
options : InterpretOptions ,
) InterpretError ! InterpretResult {
2022-11-11 01:51:02 +00:00
const tree = interpreter . getHandle ( ) . tree ;
2022-10-28 04:59:24 +01:00
const tags = tree . nodes . items ( . tag ) ;
const data = tree . nodes . items ( . data ) ;
const main_tokens = tree . nodes . items ( . main_token ) ;
switch ( tags [ node_idx ] ) {
. container_decl ,
. container_decl_trailing ,
. container_decl_arg ,
. container_decl_arg_trailing ,
. container_decl_two ,
. container_decl_two_trailing ,
2022-10-29 06:46:22 +01:00
// .tagged_union, // TODO: Fix these
// .tagged_union_trailing,
// .tagged_union_two,
// .tagged_union_two_trailing,
// .tagged_union_enum_tag,
// .tagged_union_enum_tag_trailing,
2022-10-28 04:59:24 +01:00
. root ,
= > {
2022-12-27 01:46:57 +00:00
const type_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ;
2022-10-28 04:59:24 +01:00
2023-01-14 13:07:52 +00:00
try interpreter . namespaces . append ( interpreter . allocator , . {
. parent = namespace ,
2022-12-27 01:46:57 +00:00
. node_idx = node_idx ,
2023-01-14 13:07:52 +00:00
. ty = undefined ,
2022-12-27 02:02:07 +00:00
} ) ;
2023-01-14 13:07:52 +00:00
const container_namespace = @intToEnum ( NamespaceIndex , interpreter . namespaces . len - 1 ) ;
2022-12-01 23:08:45 +00:00
2023-01-06 13:12:29 +00:00
var fields = std . ArrayListUnmanaged ( InternPool . Struct . Field ) { } ;
2023-01-14 20:30:52 +00:00
defer fields . deinit ( interpreter . allocator ) ;
2022-10-28 04:59:24 +01:00
var buffer : [ 2 ] Ast . Node . Index = undefined ;
const members = ast . declMembers ( tree , node_idx , & buffer ) ;
for ( members ) | member | {
2023-01-04 10:11:48 +00:00
const container_field = ast . containerField ( tree , member ) orelse {
2023-01-14 13:07:52 +00:00
_ = try interpreter . interpret ( member , container_namespace , options ) ;
2022-12-27 01:46:57 +00:00
continue ;
} ;
2022-12-01 23:08:45 +00:00
2023-01-14 13:07:52 +00:00
var init_type_value = try ( try interpreter . interpret ( container_field . ast . type_expr , container_namespace , . { } ) ) . getValue ( ) ;
2022-10-28 04:59:24 +01:00
2023-01-04 10:11:48 +00:00
var default_value = if ( container_field . ast . value_expr = = 0 )
2022-12-27 01:46:57 +00:00
IPIndex . none
else
2023-01-14 13:07:52 +00:00
( try ( try interpreter . interpret ( container_field . ast . value_expr , container_namespace , . { } ) ) . getValue ( ) ) . val ; // TODO check ty
2022-12-27 01:46:57 +00:00
if ( init_type_value . ty ! = type_type ) {
try interpreter . recordError (
2023-01-04 10:11:48 +00:00
container_field . ast . type_expr ,
2022-12-27 01:46:57 +00:00
" expected_type " ,
2023-01-17 19:23:27 +00:00
try std . fmt . allocPrint ( interpreter . allocator , " expected type 'type', found '{}' " , . { init_type_value . ty . fmtType ( interpreter . ip ) } ) ,
2022-12-27 01:46:57 +00:00
) ;
continue ;
2022-10-28 04:59:24 +01:00
}
2022-12-27 01:46:57 +00:00
const field : InternPool . Struct . Field = . {
2023-01-06 13:12:29 +00:00
. name = tree . tokenSlice ( container_field . ast . main_token ) ,
2022-12-27 01:46:57 +00:00
. ty = init_type_value . val ,
. default_value = default_value ,
2023-01-06 13:38:28 +00:00
. alignment = 0 , // TODO,
2022-12-27 01:46:57 +00:00
. is_comptime = false , // TODO
} ;
2023-01-14 20:30:52 +00:00
try fields . append ( interpreter . allocator , field ) ;
2022-10-28 04:59:24 +01:00
}
2022-12-01 23:08:45 +00:00
const struct_type = try interpreter . ip . get ( interpreter . allocator , IPKey {
. struct_type = . {
2023-01-06 13:12:29 +00:00
. fields = fields . items ,
2023-01-14 13:07:52 +00:00
. namespace = namespace ,
2023-01-04 10:11:48 +00:00
. layout = . Auto , // TODO
. backing_int_ty = . none , // TODO
2022-12-01 23:08:45 +00:00
} ,
} ) ;
2023-01-14 13:07:52 +00:00
interpreter . namespaces . items ( . ty ) [ @enumToInt ( container_namespace ) ] = struct_type ;
2022-12-01 23:08:45 +00:00
2022-10-28 04:59:24 +01:00
return InterpretResult { . value = Value {
2022-11-01 03:36:13 +00:00
. interpreter = interpreter ,
2022-10-28 04:59:24 +01:00
. node_idx = node_idx ,
2022-12-01 23:08:45 +00:00
. ty = type_type ,
. val = struct_type ,
2022-10-28 04:59:24 +01:00
} } ;
} ,
2023-01-20 18:28:25 +00:00
. error_set_decl = > {
// TODO
return InterpretResult { . nothing = { } } ;
} ,
2022-10-28 04:59:24 +01:00
. global_var_decl ,
. local_var_decl ,
. aligned_var_decl ,
. simple_var_decl ,
= > {
2023-01-14 13:07:52 +00:00
var decls = & interpreter . namespaces . items ( . decls ) [ @enumToInt ( namespace ) ] ;
2022-10-29 22:28:44 +01:00
2023-01-14 13:07:52 +00:00
const name = analysis . getDeclName ( tree , node_idx ) . ? ;
if ( decls . contains ( name ) )
return InterpretResult { . nothing = { } } ;
2022-10-29 22:28:44 +01:00
2023-01-14 13:07:52 +00:00
const decl = ast . varDecl ( tree , node_idx ) . ? ;
if ( decl . ast . init_node = = 0 )
return InterpretResult { . nothing = { } } ;
const init_type_value = try ( ( try interpreter . interpret ( decl . ast . init_node , namespace , . { } ) ) . getValue ( ) ) ;
try decls . putNoClobber ( interpreter . allocator , name , . {
. name = name ,
. ty = init_type_value . ty ,
. val = init_type_value . val ,
. alignment = 0 , // TODO
. address_space = . generic , // TODO
. is_pub = true , // TODO
. is_exported = false , // TODO
} ) ;
2022-10-28 04:59:24 +01:00
2022-11-11 01:51:02 +00:00
// TODO: Am I a dumbo shrimp? (e.g. is this tree shaking correct? works on my machine so like...)
// if (scope.?.scopeKind() != .container) {
2022-12-27 01:46:57 +00:00
// if (scope.?.node_idx != 0)
2023-01-14 13:07:52 +00:00
// _ = try decls.getPtr(name).?.getValue();
2022-11-01 03:36:13 +00:00
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
} ,
. block ,
. block_semicolon ,
. block_two ,
. block_two_semicolon ,
= > {
2023-01-14 13:07:52 +00:00
try interpreter . namespaces . append ( interpreter . allocator , . {
. parent = namespace ,
2022-12-27 01:46:57 +00:00
. node_idx = node_idx ,
2023-01-14 13:07:52 +00:00
. ty = . none ,
2022-12-27 02:02:07 +00:00
} ) ;
2023-01-14 13:07:52 +00:00
const block_namespace = @intToEnum ( NamespaceIndex , interpreter . namespaces . len - 1 ) ;
2022-10-28 04:59:24 +01:00
var buffer : [ 2 ] Ast . Node . Index = undefined ;
const statements = ast . blockStatements ( tree , node_idx , & buffer ) . ? ;
for ( statements ) | idx | {
2023-01-14 13:07:52 +00:00
const ret = try interpreter . interpret ( idx , block_namespace , options ) ;
2022-10-28 04:59:24 +01:00
switch ( ret ) {
. @ " break " = > | lllll | {
2023-01-14 13:07:52 +00:00
const maybe_block_label_string = if ( interpreter . namespaces . get ( @enumToInt ( namespace ) ) . getLabel ( tree ) ) | i | tree . tokenSlice ( i ) else null ;
2022-10-28 04:59:24 +01:00
if ( lllll ) | l | {
if ( maybe_block_label_string ) | ls | {
if ( std . mem . eql ( u8 , l , ls ) ) {
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
} else return ret ;
} else return ret ;
} else {
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
}
} ,
. break_with_value = > | bwv | {
2023-01-14 13:07:52 +00:00
const maybe_block_label_string = if ( interpreter . namespaces . get ( @enumToInt ( namespace ) ) . getLabel ( tree ) ) | i | tree . tokenSlice ( i ) else null ;
2022-10-28 04:59:24 +01:00
if ( bwv . label ) | l | {
if ( maybe_block_label_string ) | ls | {
if ( std . mem . eql ( u8 , l , ls ) ) {
return InterpretResult { . value = bwv . value } ;
} else return ret ;
} else return ret ;
} else {
return InterpretResult { . value = bwv . value } ;
}
} ,
. @ " return " , . return_with_value = > return ret ,
else = > { } ,
}
}
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
} ,
. identifier = > {
2023-01-14 13:07:52 +00:00
const value = offsets . nodeToSlice ( tree , node_idx ) ;
2022-10-28 04:59:24 +01:00
2023-01-20 18:20:42 +00:00
const simples = std . ComptimeStringMap ( InternPool . Simple , . {
. { " anyerror " , . anyerror } ,
. { " anyframe " , . @ " anyframe " } ,
. { " anyopaque " , . anyopaque } ,
. { " bool " , . bool } ,
. { " c_int " , . c_int } ,
. { " c_long " , . c_long } ,
. { " c_longdouble " , . c_longdouble } ,
. { " c_longlong " , . c_longlong } ,
. { " c_short " , . c_short } ,
. { " c_uint " , . c_uint } ,
. { " c_ulong " , . c_ulong } ,
. { " c_ulonglong " , . c_ulonglong } ,
. { " c_ushort " , . c_ushort } ,
. { " comptime_float " , . comptime_float } ,
. { " comptime_int " , . comptime_int } ,
. { " f128 " , . f128 } ,
. { " f16 " , . f16 } ,
. { " f32 " , . f32 } ,
. { " f64 " , . f64 } ,
. { " f80 " , . f80 } ,
. { " false " , . bool_false } ,
. { " isize " , . isize } ,
. { " noreturn " , . noreturn } ,
. { " null " , . null_value } ,
. { " true " , . bool_true } ,
. { " type " , . type } ,
. { " undefined " , . undefined_value } ,
. { " usize " , . usize } ,
. { " void " , . void } ,
} ) ;
if ( simples . get ( value ) ) | simple | {
2022-10-28 04:59:24 +01:00
return InterpretResult { . value = Value {
2022-11-01 03:36:13 +00:00
. interpreter = interpreter ,
2022-10-28 04:59:24 +01:00
. node_idx = node_idx ,
2023-01-20 18:20:42 +00:00
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = simple . toType ( ) } ) ,
. val = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = simple } ) ,
2022-10-28 04:59:24 +01:00
} } ;
2023-01-20 18:20:42 +00:00
}
if ( value . len > = 2 and ( value [ 0 ] = = 'u' or value [ 0 ] = = 'i' ) ) blk : {
2022-10-28 04:59:24 +01:00
return InterpretResult { . value = Value {
2022-11-01 03:36:13 +00:00
. interpreter = interpreter ,
2022-10-28 04:59:24 +01:00
. node_idx = node_idx ,
2022-12-01 23:08:45 +00:00
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ,
. val = try interpreter . ip . get ( interpreter . allocator , IPKey { . int_type = . {
. signedness = if ( value [ 0 ] = = 'u' ) . unsigned else . signed ,
2023-01-20 18:20:42 +00:00
. bits = std . fmt . parseInt ( u16 , value [ 1 . . ] , 10 ) catch break : blk ,
2022-12-01 23:08:45 +00:00
} } ) ,
2022-10-28 04:59:24 +01:00
} } ;
}
// Logic to find identifiers in accessible scopes
2023-01-14 20:49:27 +00:00
const decl = interpreter . huntItDown ( namespace , value , options ) catch | err | switch ( err ) {
error . IdentifierNotFound = > | e | {
try interpreter . recordError (
node_idx ,
" undeclared_identifier " ,
try std . fmt . allocPrint ( interpreter . allocator , " use of undeclared identifier '{s}' " , . { value } ) ,
) ;
return e ;
} ,
2022-12-27 01:46:57 +00:00
} ;
return InterpretResult { . value = Value {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = decl . ty ,
. val = decl . val ,
} } ;
2022-10-28 04:59:24 +01:00
} ,
2022-10-29 06:46:22 +01:00
. field_access = > {
if ( data [ node_idx ] . rhs = = 0 ) return error . CriticalAstFailure ;
2022-12-15 22:01:42 +00:00
const rhs_str = tree . tokenSlice ( data [ node_idx ] . rhs ) ;
2022-10-29 06:46:22 +01:00
2023-01-14 13:07:52 +00:00
var ir = try interpreter . interpret ( data [ node_idx ] . lhs , namespace , options ) ;
2022-10-29 06:46:22 +01:00
var irv = try ir . getValue ( ) ;
2023-01-14 13:07:52 +00:00
const lhs_namespace = interpreter . ip . indexToKey ( irv . val ) . getNamespace ( ) ;
2022-12-27 01:46:57 +00:00
2023-01-14 20:49:27 +00:00
var scope_sub_decl = irv . interpreter . huntItDown ( lhs_namespace , rhs_str , options ) catch | err | switch ( err ) {
error . IdentifierNotFound = > | e | {
try interpreter . recordError (
node_idx ,
" undeclared_identifier " ,
try std . fmt . allocPrint ( interpreter . allocator , " use of undeclared identifier '{s}' " , . { rhs_str } ) ,
) ;
return e ;
} ,
2022-10-30 08:07:49 +00:00
} ;
2022-10-29 06:46:22 +01:00
2022-12-27 01:46:57 +00:00
return InterpretResult { . value = Value {
. interpreter = interpreter ,
. node_idx = data [ node_idx ] . rhs ,
. ty = scope_sub_decl . ty ,
. val = scope_sub_decl . val ,
} } ;
2022-10-29 06:46:22 +01:00
} ,
2022-10-28 04:59:24 +01:00
. grouped_expression = > {
2023-01-14 13:07:52 +00:00
return try interpreter . interpret ( data [ node_idx ] . lhs , namespace , options ) ;
2022-10-28 04:59:24 +01:00
} ,
. @ " break " = > {
const label = if ( data [ node_idx ] . lhs = = 0 ) null else tree . tokenSlice ( data [ node_idx ] . lhs ) ;
return if ( data [ node_idx ] . rhs = = 0 )
InterpretResult { . @ " break " = label }
else
2023-01-14 13:07:52 +00:00
InterpretResult { . break_with_value = . { . label = label , . value = try ( try interpreter . interpret ( data [ node_idx ] . rhs , namespace , options ) ) . getValue ( ) } } ;
2022-10-28 04:59:24 +01:00
} ,
. @ " return " = > {
return if ( data [ node_idx ] . lhs = = 0 )
InterpretResult { . @ " return " = { } }
else
2023-01-14 13:07:52 +00:00
InterpretResult { . return_with_value = try ( try interpreter . interpret ( data [ node_idx ] . lhs , namespace , options ) ) . getValue ( ) } ;
2022-10-28 04:59:24 +01:00
} ,
2023-01-14 13:07:52 +00:00
. @ " if " ,
. if_simple ,
= > {
2023-01-20 18:28:25 +00:00
const if_info = ast . ifFull ( tree , node_idx ) ;
2022-10-28 04:59:24 +01:00
// TODO: Don't evaluate runtime ifs
// if (options.observe_values) {
2023-01-20 18:28:25 +00:00
const ir = try interpreter . interpret ( if_info . ast . cond_expr , namespace , options ) ;
2022-12-27 01:46:57 +00:00
const false_value = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool_false } ) ;
const true_value = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool_true } ) ;
const condition = ( try ir . getValue ( ) ) . val ;
std . debug . assert ( condition = = false_value or condition = = true_value ) ;
if ( condition = = true_value ) {
2023-01-20 18:28:25 +00:00
return try interpreter . interpret ( if_info . ast . then_expr , namespace , options ) ;
2022-10-28 04:59:24 +01:00
} else {
2023-01-20 18:28:25 +00:00
if ( if_info . ast . else_expr ! = 0 ) {
return try interpreter . interpret ( if_info . ast . else_expr , namespace , options ) ;
2022-10-31 05:51:51 +00:00
} else return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
}
} ,
. equal_equal = > {
2023-01-14 13:07:52 +00:00
var a = try interpreter . interpret ( data [ node_idx ] . lhs , namespace , options ) ;
var b = try interpreter . interpret ( data [ node_idx ] . rhs , namespace , options ) ;
2022-12-01 23:08:45 +00:00
return InterpretResult {
. value = Value {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool } ) ,
2022-12-27 01:46:57 +00:00
. val = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = if ( a . value . val = = b . value . val ) . bool_true else . bool_false } ) , // TODO eql function required?
2022-12-01 23:08:45 +00:00
} ,
} ;
2022-10-28 04:59:24 +01:00
} ,
. number_literal = > {
const s = tree . getNodeSource ( node_idx ) ;
const nl = std . zig . parseNumberLiteral ( s ) ;
2022-10-31 05:51:51 +00:00
2022-12-01 23:08:45 +00:00
if ( nl = = . failure ) return error . CriticalAstFailure ;
2023-01-20 18:28:25 +00:00
const number_type = try interpreter . ip . get ( interpreter . allocator , IPKey {
2022-12-01 23:08:45 +00:00
. simple = if ( nl = = . float ) . comptime_float else . comptime_int ,
} ) ;
const value = try interpreter . ip . get (
interpreter . allocator ,
switch ( nl ) {
. float = > IPKey {
2023-01-20 18:28:25 +00:00
. float_128_value = try std . fmt . parseFloat ( f128 , s ) ,
2022-12-01 23:08:45 +00:00
} ,
. int = > if ( s [ 0 ] = = '-' ) IPKey {
. int_i64_value = try std . fmt . parseInt ( i64 , s , 0 ) ,
} else IPKey {
. int_u64_value = try std . fmt . parseInt ( u64 , s , 0 ) ,
} ,
. big_int = > @panic ( " TODO: implement big int " ) ,
. failure = > return error . CriticalAstFailure ,
2022-10-28 04:59:24 +01:00
} ,
2022-12-01 23:08:45 +00:00
) ;
return InterpretResult { . value = Value {
. interpreter = interpreter ,
. node_idx = node_idx ,
2023-01-20 18:28:25 +00:00
. ty = number_type ,
2022-12-01 23:08:45 +00:00
. val = value ,
} } ;
2022-10-28 04:59:24 +01:00
} ,
. assign ,
. assign_bit_and ,
. assign_bit_or ,
. assign_shl ,
. assign_shr ,
. assign_bit_xor ,
. assign_div ,
. assign_sub ,
. assign_sub_wrap ,
. assign_mod ,
. assign_add ,
. assign_add_wrap ,
. assign_mul ,
. assign_mul_wrap ,
= > {
// TODO: Actually consider operators
2022-11-08 20:54:30 +00:00
if ( std . mem . eql ( u8 , tree . getNodeSource ( data [ node_idx ] . lhs ) , " _ " ) ) {
2023-01-14 13:07:52 +00:00
_ = try interpreter . interpret ( data [ node_idx ] . rhs , namespace , options ) ;
2022-11-08 20:54:30 +00:00
return InterpretResult { . nothing = { } } ;
}
2022-10-28 04:59:24 +01:00
2023-01-14 13:07:52 +00:00
var ir = try interpreter . interpret ( data [ node_idx ] . lhs , namespace , options ) ;
2022-10-31 20:00:02 +00:00
var to_value = try ir . getValue ( ) ;
2023-01-14 13:07:52 +00:00
var from_value = ( try ( try interpreter . interpret ( data [ node_idx ] . rhs , namespace , options ) ) . getValue ( ) ) ;
2022-10-31 20:00:02 +00:00
2023-01-20 18:28:25 +00:00
// TODO report error
_ = try interpreter . ip . cast ( interpreter . allocator , to_value . ty , from_value . ty , builtin . target ) ;
2022-10-28 04:59:24 +01:00
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
} ,
// .@"switch",
// .switch_comma,
// => {
// const cond = data[node_idx].lhs;
// const extra = tree.extraData(data[node_idx].rhs, Ast.Node.SubRange);
// const cases = tree.extra_data[extra.start..extra.end];
// for (cases) |case| {
// const switch_case: Ast.full.SwitchCase = switch (tags[case]) {
// .switch_case => tree.switchCase(case),
// .switch_case_one => tree.switchCaseOne(case),
// else => continue,
// };
// }
// },
. builtin_call ,
. builtin_call_comma ,
. builtin_call_two ,
. builtin_call_two_comma ,
= > {
var buffer : [ 2 ] Ast . Node . Index = undefined ;
const params = ast . builtinCallParams ( tree , node_idx , & buffer ) . ? ;
const call_name = tree . tokenSlice ( main_tokens [ node_idx ] ) ;
if ( std . mem . eql ( u8 , call_name , " @compileLog " ) ) {
2022-10-31 20:00:02 +00:00
var final = std . ArrayList ( u8 ) . init ( interpreter . allocator ) ;
var writer = final . writer ( ) ;
try writer . writeAll ( " log: " ) ;
for ( params ) | param , index | {
2023-01-14 13:07:52 +00:00
var value = ( try interpreter . interpret ( param , namespace , options ) ) . maybeGetValue ( ) orelse {
2022-10-31 20:00:02 +00:00
try writer . writeAll ( " indeterminate " ) ;
continue ;
} ;
2023-01-17 19:23:27 +00:00
try writer . print ( " @as({}, {}) " , . { value . ty . fmtType ( interpreter . ip ) , value . val . fmtValue ( value . ty , interpreter . ip ) } ) ;
2022-10-31 20:00:02 +00:00
if ( index ! = params . len - 1 )
try writer . writeAll ( " , " ) ;
}
2022-12-02 20:14:58 +00:00
try interpreter . recordError ( node_idx , " compile_log " , try final . toOwnedSlice ( ) ) ;
2022-10-31 20:00:02 +00:00
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
}
2022-10-28 19:24:38 +01:00
if ( std . mem . eql ( u8 , call_name , " @compileError " ) ) {
2022-10-31 20:00:02 +00:00
// TODO: Add message
try interpreter . recordError ( node_idx , " compile_error " , try std . fmt . allocPrint ( interpreter . allocator , " compile error " , . { } ) ) ;
2022-10-31 05:51:51 +00:00
return InterpretResult { . @ " return " = { } } ;
2022-10-28 19:24:38 +01:00
}
2022-10-29 22:28:44 +01:00
if ( std . mem . eql ( u8 , call_name , " @import " ) ) {
if ( params . len = = 0 ) return error . InvalidBuiltin ;
const import_param = params [ 0 ] ;
if ( tags [ import_param ] ! = . string_literal ) return error . InvalidBuiltin ;
const import_str = tree . tokenSlice ( main_tokens [ import_param ] ) ;
2022-11-11 01:51:02 +00:00
log . info ( " Resolving {s} from {s} " , . { import_str [ 1 . . import_str . len - 1 ] , interpreter . uri } ) ;
// TODO: Implement root support
if ( std . mem . eql ( u8 , import_str [ 1 . . import_str . len - 1 ] , " root " ) ) {
return InterpretResult { . value = Value {
. interpreter = interpreter ,
. node_idx = node_idx ,
2022-12-27 01:46:57 +00:00
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . struct_type = . {
2023-01-06 13:12:29 +00:00
. fields = & . { } ,
2023-01-04 10:11:48 +00:00
. namespace = . none ,
2022-12-27 01:46:57 +00:00
. layout = . Auto ,
2023-01-20 18:28:25 +00:00
. backing_int_ty = . none ,
2022-12-27 01:46:57 +00:00
} } ) ,
. val = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . undefined_value } ) ,
2022-11-11 01:51:02 +00:00
} } ;
}
var import_uri = ( try interpreter . document_store . uriFromImportStr ( interpreter . allocator , interpreter . getHandle ( ) . * , import_str [ 1 . . import_str . len - 1 ] ) ) orelse return error . ImportFailure ;
2022-10-29 22:28:44 +01:00
defer interpreter . allocator . free ( import_uri ) ;
var handle = interpreter . document_store . getOrLoadHandle ( import_uri ) orelse return error . ImportFailure ;
try interpreter . document_store . ensureInterpreterExists ( handle . uri ) ;
2022-12-27 02:02:07 +00:00
return InterpretResult {
. value = Value {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ,
2023-01-20 18:28:25 +00:00
. val = . none , // TODO
2022-12-27 02:02:07 +00:00
} ,
} ;
2022-10-29 22:28:44 +01:00
}
2022-10-30 08:07:49 +00:00
if ( std . mem . eql ( u8 , call_name , " @TypeOf " ) ) {
if ( params . len ! = 1 ) return error . InvalidBuiltin ;
2023-01-14 13:07:52 +00:00
const value = try ( try interpreter . interpret ( params [ 0 ] , namespace , options ) ) . getValue ( ) ;
2022-10-30 08:07:49 +00:00
return InterpretResult { . value = Value {
2022-11-01 03:36:13 +00:00
. interpreter = interpreter ,
2022-10-30 08:07:49 +00:00
. node_idx = node_idx ,
2022-12-01 23:08:45 +00:00
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ,
2023-01-06 13:12:29 +00:00
. val = value . ty ,
2022-10-30 08:07:49 +00:00
} } ;
}
if ( std . mem . eql ( u8 , call_name , " @hasDecl " ) ) {
if ( params . len ! = 2 ) return error . InvalidBuiltin ;
2023-01-14 13:07:52 +00:00
const value = try ( try interpreter . interpret ( params [ 0 ] , namespace , options ) ) . getValue ( ) ;
const field_name = try ( try interpreter . interpret ( params [ 1 ] , namespace , options ) ) . getValue ( ) ;
2022-10-30 08:07:49 +00:00
2022-12-27 01:46:57 +00:00
const type_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ;
if ( value . ty ! = type_type ) return error . InvalidBuiltin ;
if ( interpreter . ip . indexToKey ( field_name . ty ) ! = . pointer_type ) return error . InvalidBuiltin ; // Check if it's a []const u8
2023-01-14 13:07:52 +00:00
const value_namespace = interpreter . ip . indexToKey ( value . val ) . getNamespace ( ) ;
if ( value_namespace = = . none ) return error . InvalidBuiltin ;
2022-10-30 08:07:49 +00:00
2023-01-14 18:17:06 +00:00
const name = interpreter . ip . indexToKey ( field_name . val ) . bytes ; // TODO add checks
2022-10-30 08:07:49 +00:00
2023-01-14 13:07:52 +00:00
const decls = interpreter . namespaces . items ( . decls ) [ @enumToInt ( value_namespace ) ] ;
2023-01-04 10:11:48 +00:00
const has_decl = decls . contains ( name ) ;
2022-12-01 23:08:45 +00:00
2022-10-30 08:07:49 +00:00
return InterpretResult { . value = Value {
2022-11-01 03:36:13 +00:00
. interpreter = interpreter ,
2022-10-30 08:07:49 +00:00
. node_idx = node_idx ,
2022-12-01 23:08:45 +00:00
. ty = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool } ) ,
. val = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = if ( has_decl ) . bool_true else . bool_false } ) ,
2022-10-30 08:07:49 +00:00
} } ;
}
2022-10-31 05:51:51 +00:00
if ( std . mem . eql ( u8 , call_name , " @as " ) ) {
if ( params . len ! = 2 ) return error . InvalidBuiltin ;
2023-01-14 13:07:52 +00:00
const as_type = try ( try interpreter . interpret ( params [ 0 ] , namespace , options ) ) . getValue ( ) ;
const value = try ( try interpreter . interpret ( params [ 1 ] , namespace , options ) ) . getValue ( ) ;
2022-10-31 05:51:51 +00:00
2022-12-27 01:46:57 +00:00
const type_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ;
2022-10-31 05:51:51 +00:00
2022-12-27 01:46:57 +00:00
if ( as_type . ty ! = type_type ) return error . InvalidBuiltin ;
2023-01-20 16:06:16 +00:00
return InterpretResult {
. value = Value {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = as_type . val ,
. val = value . val , // TODO port Sema.coerceExtra to InternPool
} ,
} ;
2022-10-31 05:51:51 +00:00
}
2022-11-10 04:46:23 +00:00
log . err ( " Builtin not implemented: {s} " , . { call_name } ) ;
2022-10-30 08:07:49 +00:00
return error . InvalidBuiltin ;
2022-10-28 04:59:24 +01:00
} ,
. string_literal = > {
2022-12-01 23:08:45 +00:00
const str = tree . getNodeSource ( node_idx ) [ 1 . . tree . getNodeSource ( node_idx ) . len - 1 ] ;
const string_literal_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . pointer_type = . {
. elem_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . array_type = . {
. child = try interpreter . ip . get ( interpreter . allocator , IPKey { . int_type = . {
. signedness = . unsigned ,
. bits = 8 ,
} } ) ,
2022-12-27 01:46:57 +00:00
. len = @intCast ( u32 , str . len ) ,
2022-12-01 23:08:45 +00:00
. sentinel = try interpreter . ip . get ( interpreter . allocator , IPKey { . int_u64_value = 0 } ) ,
} } ) ,
. sentinel = . none ,
. alignment = 0 ,
2022-12-27 01:46:57 +00:00
. size = . One ,
2022-12-01 23:08:45 +00:00
. is_const = true ,
. is_volatile = false ,
. is_allowzero = false ,
. address_space = . generic ,
} } ) ;
2023-01-20 18:28:25 +00:00
return InterpretResult { . value = Value {
2022-11-01 03:36:13 +00:00
. interpreter = interpreter ,
2022-10-28 04:59:24 +01:00
. node_idx = node_idx ,
2022-12-01 23:08:45 +00:00
. ty = string_literal_type ,
2023-01-14 20:49:27 +00:00
. val = try interpreter . ip . get ( interpreter . allocator , IPKey { . bytes = str } ) ,
2023-01-20 18:28:25 +00:00
} } ;
2022-10-28 04:59:24 +01:00
} ,
// TODO: Add comptime autodetection; e.g. const MyArrayList = std.ArrayList(u8)
. @ " comptime " = > {
2023-01-14 13:07:52 +00:00
return try interpreter . interpret ( data [ node_idx ] . lhs , namespace , . { } ) ;
2022-10-28 04:59:24 +01:00
} ,
2023-01-14 13:07:52 +00:00
. fn_proto ,
. fn_proto_multi ,
. fn_proto_one ,
. fn_proto_simple ,
. fn_decl ,
= > {
2023-01-04 10:11:48 +00:00
var buf : [ 1 ] Ast . Node . Index = undefined ;
const func = ast . fnProto ( tree , node_idx , & buf ) . ? ;
2022-10-28 04:59:24 +01:00
2022-12-01 23:08:45 +00:00
// TODO: Resolve function type
2022-10-28 04:59:24 +01:00
2023-01-04 10:11:48 +00:00
const type_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ;
const function_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . function_type = . {
. calling_convention = . Unspecified ,
. alignment = 0 ,
. is_generic = false ,
. is_var_args = false ,
. return_type = IPIndex . none ,
. args = & . { } ,
} } ) ;
2022-10-28 04:59:24 +01:00
// var it = func.iterate(&tree);
// while (ast.nextFnParam(&it)) |param| {
// // Add parameter decls
// if (param.name_token) |name_token| {
// // TODO: Think of new method for functions
// if ((try interpreter.interpret(param.type_expr, func_scope_idx, .{ .observe_values = true, .is_comptime = true })).maybeGetValue()) |value| {
// try interpreter.addDeclaration(func_scope_idx, value.value_data.@"type");
// try fnd.params.append(interpreter.allocator, interpreter.declarations.items.len - 1);
// } else {
// try interpreter.addDeclaration(parent_scope_idx.?, .{
// .node_idx = node_idx,
// .name = tree.tokenSlice(name_token),
// .scope_idx = func_scope_idx, // orelse std.math.maxInt(usize),
// .@"value" = undefined,
// .@"type" = interpreter.createType(0, .{ .@"anytype" = .{} }),
// });
// try fnd.params.append(interpreter.allocator, interpreter.declarations.items.len - 1);
// }
// }
// }
// if ((try interpreter.interpret(func.ast.return_type, func_scope_idx, .{ .observe_values = true, .is_comptime = true })).maybeGetValue()) |value|
// fnd.return_type = value.value_data.@"type";
2023-01-04 10:11:48 +00:00
const name = offsets . tokenToSlice ( tree , func . name_token . ? ) ;
2022-12-27 01:46:57 +00:00
2023-01-04 10:11:48 +00:00
if ( namespace ! = . none ) {
const decls = & interpreter . namespaces . items ( . decls ) [ @enumToInt ( namespace ) ] ;
try decls . put ( interpreter . allocator , name , . {
. name = name ,
. ty = type_type ,
. val = function_type ,
. alignment = 0 , // TODO
. address_space = . generic , // TODO
. is_pub = false , // TODO
. is_exported = false , // TODO
} ) ;
}
2022-10-28 04:59:24 +01:00
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
} ,
. call ,
. call_comma ,
. async_call ,
. async_call_comma ,
. call_one ,
. call_one_comma ,
. async_call_one ,
. async_call_one_comma ,
= > {
2022-10-28 19:24:38 +01:00
var params : [ 1 ] Ast . Node . Index = undefined ;
2023-01-14 13:07:52 +00:00
const call_full = ast . callFull ( tree , node_idx , & params ) . ? ;
2022-10-28 04:59:24 +01:00
2022-10-28 19:24:38 +01:00
var args = try std . ArrayListUnmanaged ( Value ) . initCapacity ( interpreter . allocator , call_full . ast . params . len ) ;
defer args . deinit ( interpreter . allocator ) ;
2022-10-28 04:59:24 +01:00
2022-10-28 19:24:38 +01:00
for ( call_full . ast . params ) | param | {
2023-01-14 13:07:52 +00:00
args . appendAssumeCapacity ( try ( try interpreter . interpret ( param , namespace , . { } ) ) . getValue ( ) ) ;
2022-10-28 19:24:38 +01:00
}
2022-10-28 04:59:24 +01:00
2023-01-14 13:07:52 +00:00
const func_id_result = try interpreter . interpret ( call_full . ast . fn_expr , namespace , . { } ) ;
2022-10-29 06:46:22 +01:00
const func_id_val = try func_id_result . getValue ( ) ;
2022-10-28 04:59:24 +01:00
2023-01-14 13:07:52 +00:00
const call_res = try interpreter . call ( namespace , func_id_val . node_idx , args . items , options ) ;
2022-10-29 06:46:22 +01:00
// TODO: Figure out call result memory model; this is actually fine because newScope
// makes this a child of the decl scope which is freed on refresh... in theory
2022-10-28 19:24:38 +01:00
return switch ( call_res . result ) {
. value = > | v | . { . value = v } ,
. nothing = > . { . nothing = { } } ,
} ;
2022-10-28 04:59:24 +01:00
} ,
2022-10-28 06:22:03 +01:00
. bool_not = > {
2023-01-14 13:07:52 +00:00
const result = try interpreter . interpret ( data [ node_idx ] . lhs , namespace , . { } ) ;
2022-12-01 23:08:45 +00:00
const bool_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool } ) ;
const value = try result . getValue ( ) ;
2023-01-20 18:28:25 +00:00
if ( value . ty ! = bool_type ) {
try interpreter . recordError ( node_idx , " invalid_deref " , try std . fmt . allocPrint ( interpreter . allocator , " expected type `bool` but got `{}` " , . { value . ty . fmtType ( interpreter . ip ) } ) ) ;
2022-12-01 23:08:45 +00:00
return error . InvalidOperation ;
}
2023-01-20 18:28:25 +00:00
const false_value = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool_false } ) ;
const true_value = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . bool_true } ) ;
std . debug . assert ( value . val = = false_value or value . val = = true_value ) ;
return InterpretResult { . value = . {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = bool_type ,
. val = if ( value . val = = false_value ) true_value else false_value ,
} } ;
2022-10-31 20:00:02 +00:00
} ,
. address_of = > {
// TODO: Make const pointers if we're drawing from a const;
// variables are the only non-const(?)
2023-01-14 13:07:52 +00:00
const result = try interpreter . interpret ( data [ node_idx ] . lhs , namespace , . { } ) ;
2022-10-31 20:00:02 +00:00
const value = ( try result . getValue ( ) ) ;
2022-12-01 23:08:45 +00:00
const pointer_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . pointer_type = . {
2022-12-27 01:46:57 +00:00
. elem_type = value . ty ,
2022-12-01 23:08:45 +00:00
. sentinel = . none ,
. alignment = 0 ,
2022-12-27 01:46:57 +00:00
. size = . One ,
2022-12-01 23:08:45 +00:00
. is_const = false ,
. is_volatile = false ,
. is_allowzero = false ,
. address_space = . generic ,
} } ) ;
return InterpretResult { . value = . {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = pointer_type ,
2023-01-06 13:12:29 +00:00
. val = value . val ,
2022-12-01 23:08:45 +00:00
} } ;
2022-10-31 20:00:02 +00:00
} ,
. deref = > {
2023-01-14 13:07:52 +00:00
const result = try interpreter . interpret ( data [ node_idx ] . lhs , namespace , . { } ) ;
2022-10-31 20:00:02 +00:00
const value = ( try result . getValue ( ) ) ;
2022-12-01 23:08:45 +00:00
const type_key = interpreter . ip . indexToKey ( value . ty ) ;
2022-10-31 20:00:02 +00:00
2022-12-27 01:46:57 +00:00
if ( type_key ! = . pointer_type ) {
2022-10-31 20:00:02 +00:00
try interpreter . recordError ( node_idx , " invalid_deref " , try std . fmt . allocPrint ( interpreter . allocator , " cannot deference non-pointer " , . { } ) ) ;
return error . InvalidOperation ;
}
2022-12-01 23:08:45 +00:00
return InterpretResult { . value = . {
. interpreter = interpreter ,
. node_idx = node_idx ,
. ty = type_key . pointer_type . elem_type ,
2023-01-06 13:12:29 +00:00
. val = value . val ,
2022-12-01 23:08:45 +00:00
} } ;
2022-10-28 06:22:03 +01:00
} ,
2022-10-28 04:59:24 +01:00
else = > {
2022-11-10 04:46:23 +00:00
log . err ( " Unhandled {any} " , . { tags [ node_idx ] } ) ;
2022-10-31 05:51:51 +00:00
return InterpretResult { . nothing = { } } ;
2022-10-28 04:59:24 +01:00
} ,
}
}
pub const CallResult = struct {
2023-01-14 13:07:52 +00:00
namespace : NamespaceIndex ,
2022-10-28 04:59:24 +01:00
result : union ( enum ) {
value : Value ,
nothing ,
} ,
} ;
pub fn call (
interpreter : * ComptimeInterpreter ,
2023-01-14 13:07:52 +00:00
namespace : NamespaceIndex ,
2022-10-28 04:59:24 +01:00
func_node_idx : Ast . Node . Index ,
arguments : [ ] const Value ,
options : InterpretOptions ,
) InterpretError ! CallResult {
2022-11-08 20:54:30 +00:00
// _ = options;
2022-10-29 22:28:44 +01:00
// TODO: type check args
2022-10-28 04:59:24 +01:00
2022-11-11 01:51:02 +00:00
const tree = interpreter . getHandle ( ) . tree ;
2022-10-28 04:59:24 +01:00
2023-01-14 20:49:27 +00:00
var buf : [ 1 ] Ast . Node . Index = undefined ;
var proto = ast . fnProto ( tree , func_node_idx , & buf ) orelse return error . CriticalAstFailure ;
2022-10-28 04:59:24 +01:00
2023-01-14 13:07:52 +00:00
// TODO: Make argument namespace to evaluate arguments in
try interpreter . namespaces . append ( interpreter . allocator , . {
. parent = namespace ,
2022-12-27 02:02:07 +00:00
. node_idx = func_node_idx ,
2023-01-14 13:07:52 +00:00
. ty = . none ,
2022-12-27 02:02:07 +00:00
} ) ;
2023-01-14 13:07:52 +00:00
const fn_namespace = @intToEnum ( NamespaceIndex , interpreter . namespaces . len - 1 ) ;
2022-12-27 02:02:07 +00:00
const type_type = try interpreter . ip . get ( interpreter . allocator , IPKey { . simple = . type } ) ;
2022-10-28 04:59:24 +01:00
2022-10-28 19:24:38 +01:00
var arg_it = proto . iterate ( & tree ) ;
var arg_index : usize = 0 ;
while ( ast . nextFnParam ( & arg_it ) ) | param | {
2022-10-29 22:28:44 +01:00
if ( arg_index > = arguments . len ) return error . MissingArguments ;
2023-01-14 13:07:52 +00:00
var tex = try ( try interpreter . interpret ( param . type_expr , fn_namespace , options ) ) . getValue ( ) ;
2022-12-27 01:46:57 +00:00
if ( tex . ty ! = type_type ) {
2022-11-08 20:54:30 +00:00
try interpreter . recordError (
param . type_expr ,
" expected_type " ,
2023-01-17 19:23:27 +00:00
std . fmt . allocPrint ( interpreter . allocator , " expected type 'type', found '{}' " , . { tex . ty . fmtType ( interpreter . ip ) } ) catch return error . CriticalAstFailure ,
2022-11-08 20:54:30 +00:00
) ;
return error . InvalidCast ;
}
2023-01-14 13:07:52 +00:00
if ( param . name_token ) | name_token | {
const name = offsets . tokenToSlice ( tree , name_token ) ;
try interpreter . namespaces . items ( . decls ) [ @enumToInt ( fn_namespace ) ] . put ( interpreter . allocator , name , . {
. name = name ,
. ty = tex . val ,
. val = arguments [ arg_index ] . val ,
. alignment = 0 , // TODO
. address_space = . generic , // TODO
. is_pub = true , // TODO
. is_exported = false , // TODO
} ) ;
2022-10-28 19:24:38 +01:00
arg_index + = 1 ;
}
}
2022-10-28 04:59:24 +01:00
const body = tree . nodes . items ( . data ) [ func_node_idx ] . rhs ;
2023-01-14 13:07:52 +00:00
const result = try interpreter . interpret ( body , fn_namespace , . { } ) ;
2022-10-28 04:59:24 +01:00
// TODO: Defers
return CallResult {
2023-01-14 13:07:52 +00:00
. namespace = fn_namespace ,
2022-10-28 04:59:24 +01:00
. result = switch ( result ) {
2022-11-08 20:54:30 +00:00
. @ " return " , . nothing = > . { . nothing = { } } , // nothing could be due to an error
2022-12-01 23:08:45 +00:00
. return_with_value = > | v | . { . value = v } ,
2022-10-28 04:59:24 +01:00
else = > @panic ( " bruh " ) ,
} ,
} ;
}