Files
raddebugger/src/eval2/eval2.h
T

687 lines
19 KiB
C

// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef EVAL2_H
#define EVAL2_H
////////////////////////////////
//~ rjf: Expression Parse Info Table Types
typedef enum E2_ExprParseKind
{
E2_ExprParseKind_Null,
E2_ExprParseKind_UnaryPrefix,
E2_ExprParseKind_UnaryPostfix,
E2_ExprParseKind_Binary,
E2_ExprParseKind_Ternary,
E2_ExprParseKind_Call,
}
E2_ExprParseKind;
////////////////////////////////
//~ rjf: Generated Code
#include "eval2/generated/eval2.meta.h"
////////////////////////////////
//~ rjf: Extended Opcodes
enum
{
E2_EvalOp_SetCtxID = RDI_EvalOp_COUNT,
E2_EvalOp_LeafMacroArgument,
};
////////////////////////////////
//~ rjf: Parse Statuses
typedef enum E2_ParseStatus
{
//- rjf: terminals
E2_ParseStatus_Good,
E2_ParseStatus_Error,
E2_ParseStatus_FirstTerminal = E2_ParseStatus_Good,
E2_ParseStatus_LastTerminal = E2_ParseStatus_Error,
//- rjf: caller-provided info
E2_ParseStatus_CheckIdentifierIsType,
E2_ParseStatus_FirstCallerRequest = E2_ParseStatus_CheckIdentifierIsType,
E2_ParseStatus_LastCallerRequest = E2_ParseStatus_CheckIdentifierIsType,
}
E2_ParseStatus;
#define e2_parse_status_is_terminal(s) (E2_ParseStatus_FirstTerminal <= (s) && (s) <= E2_ParseStatus_LastTerminal)
#define e2_parse_status_is_caller_request(s) (E2_ParseStatus_FirstCallerRequest <= (s) && (s) <= E2_ParseStatus_LastCallerRequest)
////////////////////////////////
//~ rjf: Compiler Statuses
typedef enum E2_CompileStatus
{
//- rjf: terminals
E2_CompileStatus_Good,
E2_CompileStatus_Error,
E2_CompileStatus_FirstTerminal = E2_CompileStatus_Good,
E2_CompileStatus_LastTerminal = E2_CompileStatus_Error,
//- rjf: caller-provided info
E2_CompileStatus_MissedIdentifierResolution,
E2_CompileStatus_NewIdentifierDefinition,
E2_CompileStatus_MemberAccess,
E2_CompileStatus_IndexAccess,
E2_CompileStatus_Call,
E2_CompileStatus_CompileTimeEval,
E2_CompileStatus_FirstCallerRequest = E2_CompileStatus_MissedIdentifierResolution,
E2_CompileStatus_LastCallerRequest = E2_CompileStatus_CompileTimeEval,
}
E2_CompileStatus;
#define e2_compile_status_is_terminal(s) (E2_CompileStatus_FirstTerminal <= (s) && (s) <= E2_CompileStatus_LastTerminal)
#define e2_compile_status_is_caller_request(s) (E2_CompileStatus_FirstCallerRequest <= (s) && (s) <= E2_CompileStatus_LastCallerRequest)
////////////////////////////////
//~ rjf: Interpretation Statuses
typedef enum E2_InterpStatus
{
//- rjf: terminals
E2_InterpStatus_Good,
E2_InterpStatus_BadRegCode,
E2_InterpStatus_MissingCtxFlag,
E2_InterpStatus_DivideByZero,
E2_InterpStatus_InsufficientStackSpace,
E2_InterpStatus_BadOpTypes,
E2_InterpStatus_UnsupportedOp,
E2_InterpStatus_BadOffset,
E2_InterpStatus_Error,
E2_InterpStatus_FirstTerminal = E2_InterpStatus_Good,
E2_InterpStatus_LastTerminal = E2_InterpStatus_Error,
//- rjf: caller-provided info
E2_InterpStatus_MissedSpaceRead,
E2_InterpStatus_NewCtxID,
E2_InterpStatus_FirstCallerRequest = E2_InterpStatus_MissedSpaceRead,
E2_InterpStatus_LastCallerRequest = E2_InterpStatus_NewCtxID,
}
E2_InterpStatus;
#define e2_interp_status_is_terminal(s) (E2_InterpStatus_FirstTerminal <= (s) && (s) <= E2_InterpStatus_LastTerminal)
#define e2_interp_status_is_caller_request(s) (E2_InterpStatus_FirstCallerRequest <= (s) && (s) <= E2_InterpStatus_LastCallerRequest)
////////////////////////////////
//~ rjf: Type Keys
typedef enum E2_TypeKeyKind
{
E2_TypeKeyKind_Null,
E2_TypeKeyKind_Basic,
E2_TypeKeyKind_DbgInfo,
E2_TypeKeyKind_Cons,
E2_TypeKeyKind_Reg,
}
E2_TypeKeyKind;
typedef struct E2_TypeKey E2_TypeKey;
struct E2_TypeKey
{
E2_TypeKeyKind kind;
U32 u32[3];
// [0] -> E_TypeKind (Basic, Cons, DbgInfo); Arch (Reg)
// [1] -> Debug Info Number (DbgInfo); Code (Reg); Type Index In Constructed (Cons)
// [2] -> Type Index In Debug Info (DbgInfo)
};
typedef struct E2_TypeKeyNode E2_TypeKeyNode;
struct E2_TypeKeyNode
{
E2_TypeKeyNode *next;
E2_TypeKey v;
};
typedef struct E2_TypeKeyList E2_TypeKeyList;
struct E2_TypeKeyList
{
E2_TypeKeyNode *first;
E2_TypeKeyNode *last;
U64 count;
};
////////////////////////////////
//~ rjf: Constructed Type Cache Types
typedef struct E2_ConsTypeParams E2_ConsTypeParams;
struct E2_ConsTypeParams
{
Arch arch;
E2_TypeKind kind;
String8 name;
E2_TypeKey direct;
U64 count;
U64 depth;
struct E2_Expr **args;
};
typedef struct E2_ConsTypeNode E2_ConsTypeNode;
struct E2_ConsTypeNode
{
E2_ConsTypeNode *id_next;
E2_ConsTypeNode *content_next;
U64 id;
E2_ConsTypeParams params;
U64 byte_size;
};
typedef struct E2_ConsTypeSlot E2_ConsTypeSlot;
struct E2_ConsTypeSlot
{
E2_ConsTypeNode *first;
E2_ConsTypeNode *last;
};
typedef struct E2_ConsTypeMap E2_ConsTypeMap;
struct E2_ConsTypeMap
{
Arena *arena;
U64 id_gen;
U64 table_start_arena_pos;
U64 slots_count;
E2_ConsTypeSlot *content_slots;
E2_ConsTypeSlot *id_slots;
};
////////////////////////////////
//~ rjf: Evaluation Values
typedef enum E2_Mode
{
E2_Mode_Type, // no value content - just type content
E2_Mode_Address, // value is an address into a space
E2_Mode_Value, // value is just a value, does not refer elsewhere
E2_Mode_COUNT
}
E2_Mode;
typedef struct E2_Val E2_Val;
struct E2_Val
{
union
{
U512 u512;
U256 u256;
U128 u128;
U64 u64;
U32 u32;
U16 u16;
U8 u8;
S64 s64;
S32 s32;
S16 s16;
S8 s8;
F64 f64;
F32 f32;
};
String8 string;
};
////////////////////////////////
//~ rjf: Evaluation "Asset" Parameters (Debug Info / Modules)
typedef U64 E2_SpaceID;
typedef struct E2_DbgInfo E2_DbgInfo;
struct E2_DbgInfo
{
DI_Key dbgi_key;
RDI_Parsed *rdi;
};
typedef struct E2_Assets E2_Assets;
struct E2_Assets
{
U32 dbg_infos_count;
E2_DbgInfo *dbg_infos;
};
////////////////////////////////
//~ rjf: Evaluation Contexts
typedef U64 E2_CtxID;
typedef U32 E2_CtxFlags;
enum
{
E2_CtxFlag_HasFrameBase = (1<<0),
E2_CtxFlag_HasCFA = (1<<1),
E2_CtxFlag_HasModuleBase = (1<<2),
E2_CtxFlag_HasTLSBase = (1<<3),
};
typedef struct E2_Ctx E2_Ctx;
struct E2_Ctx
{
// rjf: base info
E2_CtxID id;
E2_SpaceID space_id;
E2_SpaceID reg_space_id;
Arch arch;
U64 addr;
// rjf: optional extensions
E2_CtxFlags flags;
U64 frame_base_addr;
U64 cfa_addr;
U64 module_base_addr;
U64 tls_base_addr;
};
////////////////////////////////
//~ rjf: Tokens
typedef enum E2_TokenKind
{
E2_TokenKind_Null,
E2_TokenKind_Whitespace,
E2_TokenKind_Comment,
E2_TokenKind_Identifier,
E2_TokenKind_Numeric,
E2_TokenKind_Symbol,
E2_TokenKind_CharLiteral,
E2_TokenKind_StringLiteral,
E2_TokenKind_COUNT
}
E2_TokenKind;
typedef struct E2_Token E2_Token;
struct E2_Token
{
E2_TokenKind kind;
U32 unused;
Rng1U64 range;
};
////////////////////////////////
//~ rjf: Expression Tree Building
typedef struct E2_ExprNode E2_ExprNode;
struct E2_ExprNode
{
E2_ExprNode *next;
struct E2_Expr *v;
};
typedef struct E2_Expr E2_Expr;
struct E2_Expr
{
E2_ExprNode *first_child;
E2_ExprNode *last_child;
U64 child_count;
E2_ExprKind kind;
U32 macro_arg_num;
Rng1U64 src_range;
String8 string;
};
typedef struct E2_ExprMapNode E2_ExprMapNode;
struct E2_ExprMapNode
{
E2_ExprMapNode *next;
String8 name;
E2_Expr *expr;
};
typedef struct E2_ExprMap E2_ExprMap;
struct E2_ExprMap
{
E2_ExprMapNode **slots;
U64 slots_count;
};
typedef struct E2_ParseTask E2_ParseTask;
struct E2_ParseTask
{
E2_ParseTask *next;
Rng1U64 src_range;
E2_ExprNode *first_child;
E2_ExprNode *last_child;
U64 child_count;
U64 child_count_target;
S64 max_precedence;
E2_ExprKind expr_kind;
String8 identifier;
String8 expected_closer;
String8 expected_splitter;
B32 splitter_is_required;
String8List macro_arg_names;
};
typedef struct E2_ParseState E2_ParseState;
struct E2_ParseState
{
U64 string_off;
E2_ParseTask *top_task;
E2_ParseTask *free_task;
U64 last_caller_request_string_off;
U64 caller_request_count;
String8 last_requested_member_name;
B32 caller_info_completes_task;
};
typedef struct E2_Msg E2_Msg;
struct E2_Msg
{
E2_Msg *next;
Rng1U64 src_range;
String8 string;
};
typedef struct E2_MsgList E2_MsgList;
struct E2_MsgList
{
E2_Msg *first;
E2_Msg *last;
U64 count;
};
typedef struct E2_Parse E2_Parse;
struct E2_Parse
{
E2_ParseStatus status;
String8 identifier;
E2_Expr *expr;
String8 member_name;
E2_Expr *params_expr;
E2_MsgList msgs;
};
////////////////////////////////
//~ rjf: IR Tree Building
typedef struct E2_IRNodePtrNode E2_IRNodePtrNode;
struct E2_IRNodePtrNode
{
E2_IRNodePtrNode *next;
struct E2_IRNode *v;
};
typedef struct E2_IRNode E2_IRNode;
struct E2_IRNode
{
E2_IRNodePtrNode *first_child;
E2_IRNodePtrNode *last_child;
U64 child_count;
RDI_EvalOp op;
String8 string;
E2_TypeKey type_key;
E2_Mode mode;
E2_Val val;
};
typedef struct E2_IdentifierMapNode E2_IdentifierMapNode;
struct E2_IdentifierMapNode
{
E2_IdentifierMapNode *next;
String8 name;
E2_IRNode *irtree;
};
typedef struct E2_IdentifierMap E2_IdentifierMap;
struct E2_IdentifierMap
{
E2_IdentifierMapNode **slots;
U64 slots_count;
};
typedef struct E2_CompileTask E2_CompileTask;
struct E2_CompileTask
{
E2_CompileTask *next;
E2_Expr *expr;
E2_ExprNode *last_compiled_child_node;
E2_IRNodePtrNode *first_irtree_child;
E2_IRNodePtrNode *last_irtree_child;
U64 irtree_child_count;
};
typedef struct E2_CompileState E2_CompileState;
struct E2_CompileState
{
E2_CompileTask *top_task;
E2_CompileTask *free_task;
U64 caller_request_count;
};
typedef struct E2_Compile E2_Compile;
struct E2_Compile
{
E2_CompileStatus status;
String8 identifier;
E2_IRNode *irtree;
String8 member_name;
E2_IRNode *params_irtree;
E2_MsgList msgs;
};
////////////////////////////////
//~ rjf: Interpretation
typedef struct E2_SpaceMapNode E2_SpaceMapNode;
struct E2_SpaceMapNode
{
E2_SpaceMapNode *next;
E2_SpaceID space_id;
MemoryMap memory_map;
};
typedef struct E2_SpaceMap E2_SpaceMap;
struct E2_SpaceMap
{
E2_SpaceMapNode **slots;
U64 slots_count;
};
typedef struct E2_InterpStackValNode E2_InterpStackValNode;
struct E2_InterpStackValNode
{
E2_InterpStackValNode *next;
E2_Val val;
};
typedef struct E2_InterpState E2_InterpState;
struct E2_InterpState
{
U64 bytecode_off;
E2_Ctx selected_ctx;
E2_InterpStackValNode *top_val;
E2_InterpStackValNode *free_val;
U64 last_caller_request_bytecode_off;
U64 caller_request_count;
};
typedef struct E2_Interp E2_Interp;
struct E2_Interp
{
E2_InterpStatus status;
E2_SpaceID space_id;
Rng1U64 missed_read_space_addr_range;
E2_CtxID ctx_id;
E2_CtxFlags missing_ctx_flags;
E2_Val val;
E2_MsgList msgs;
};
////////////////////////////////
//~ rjf: Globals
thread_static E2_Assets *e2_assets = 0;
thread_static E2_ConsTypeMap *e2_cons_type_map = 0;
read_only global E2_ConsTypeNode e2_cons_type_node_nil = {&e2_cons_type_node_nil, &e2_cons_type_node_nil};
read_only global E2_DbgInfo e2_dbg_info_nil = {{0}, &rdi_parsed_nil};
read_only global E2_Expr e2_expr_nil = {0};
read_only global E2_IRNode e2_irnode_nil = {0};
////////////////////////////////
//~ rjf: Space -> Memory Map Helpers
internal void e2_space_map_push(Arena *arena, E2_SpaceMap *map, E2_SpaceID space_id, Rng1U64 addr_range, void *data);
internal U64 e2_space_map_read(E2_SpaceMap *map, E2_SpaceID space_id, Rng1U64 addr_range, void *out);
////////////////////////////////
//~ rjf: Name -> Expr Map Helpers
internal void e2_expr_map_push(Arena *arena, E2_ExprMap *map, String8 name, E2_Expr *expr);
internal E2_Expr *e2_expr_from_name(E2_ExprMap *map, String8 name);
////////////////////////////////
//~ rjf: Identifier Map Helpers
internal void e2_identifier_map_push(Arena *arena, E2_IdentifierMap *map, String8 name, E2_IRNode *irtree);
internal E2_IRNode *e2_irtree_from_identifier(E2_IdentifierMap *map, String8 name);
////////////////////////////////
//~ rjf: Messages
internal E2_Msg *e2_msg(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, String8 string);
internal E2_Msg *e2_msgf(Arena *arena, E2_MsgList *msgs, Rng1U64 src_range, char *fmt, ...);
////////////////////////////////
//~ rjf: Assets
internal void e2_select_assets(E2_Assets *assets);
internal E2_DbgInfo *e2_dbgi_from_num(U32 num);
////////////////////////////////
//~ rjf: Constructed Types
internal E2_ConsTypeMap *e2_cons_type_map_alloc(void);
internal void e2_select_cons_type_map(E2_ConsTypeMap *map);
internal B32 e2_cons_type_params_match(E2_ConsTypeParams *a, E2_ConsTypeParams *b);
internal E2_ConsTypeNode *e2_cons_type_node_from_params(E2_ConsTypeParams *params);
internal E2_ConsTypeNode *e2_cons_type_node_from_id(U64 id);
internal E2_TypeKey e2_type_key_from_cons_type_node(E2_ConsTypeNode *node);
////////////////////////////////
//~ rjf: Type Keys
//- rjf: enums
internal E2_TypeKind e2_type_kind_from_rdi(RDI_TypeKind k);
internal RDI_EvalTypeGroup e2_type_group_from_kind(E2_TypeKind k);
internal B32 e2_type_kind_is_ptr_or_ref(E2_TypeKind k);
internal B32 e2_type_kind_is_integer(E2_TypeKind k);
internal B32 e2_type_kind_is_float(E2_TypeKind k);
internal B32 e2_type_kind_is_signed(E2_TypeKind k);
internal B32 e2_type_kind_is_unsigned(E2_TypeKind k);
//- rjf: basic key constructors
internal E2_TypeKey e2_type_key_zero(void);
internal E2_TypeKey e2_type_key_basic(E2_TypeKind kind);
internal E2_TypeKey e2_type_key_dbgi(E2_TypeKind kind, U32 dbg_info_num, U32 type_idx);
internal E2_TypeKey e2_type_key_reg(Arch arch, ARCH_RegCode reg_code);
//- rjf: constructed type constructor
internal E2_TypeKey e2_type_key_cons_(E2_ConsTypeParams *params);
#define e2_type_key_cons(k, ...) e2_type_key_cons_(&(E2_ConsTypeParams){.kind = (k), __VA_ARGS__})
//- rjf: constructed type constructor helpers
#define e2_type_key_cons_array(element_type_key, count_, ...) e2_type_key_cons(E2_TypeKind_Array, .direct = (element_type_key), .count = (count_), __VA_ARGS__)
#define e2_type_key_cons_ptr(arch, ptee_type_key, ...) e2_type_key_cons(E2_TypeKind_Ptr, .direct = (ptee_type_key), __VA_ARGS__)
//- rjf: basic type key type functions
internal B32 e2_type_key_match(E2_TypeKey a, E2_TypeKey b);
//- rjf: type key -> info
internal E2_TypeKind e2_type_kind_from_key(E2_TypeKey k);
internal U64 e2_byte_size_from_type_key(E2_TypeKey k);
internal U32 e2_dbgi_num_from_type_key(E2_TypeKey k);
internal E2_DbgInfo *e2_dbgi_from_type_key(E2_TypeKey k);
internal U32 e2_dbgi_type_idx_from_key(E2_TypeKey k);
internal U64 e2_cons_type_id_from_key(E2_TypeKey k);
internal U64 e2_shift_from_type_key(E2_TypeKey k);
internal U64 e2_mask_count_from_type_key(E2_TypeKey k);
internal Arch e2_arch_from_type_key(E2_TypeKey k);
//- rjf: type deep matches
internal B32 e2_type_deep_match(E2_TypeKey l, E2_TypeKey r);
//- rjf: type graph traversal primitives
internal E2_TypeKey e2_type_key_direct(E2_TypeKey k);
internal E2_TypeKey e2_type_key_owner(E2_TypeKey k);
//- rjf: type unwrapping (helpers for advancing past categories of direct type chains)
typedef U32 E2_TypeUnwrapFlags;
enum
{
E2_TypeUnwrapFlag_Modifiers = (1<<0),
E2_TypeUnwrapFlag_Pointers = (1<<1),
E2_TypeUnwrapFlag_Lenses = (1<<2),
E2_TypeUnwrapFlag_Meta = (1<<3),
E2_TypeUnwrapFlag_Enums = (1<<4),
E2_TypeUnwrapFlag_Aliases = (1<<5),
E2_TypeUnwrapFlag_Bitfields = (1<<6),
E2_TypeUnwrapFlag_All = 0xffffffff,
E2_TypeUnwrapFlag_AllDecorative = (E2_TypeUnwrapFlag_All & ~(E2_TypeUnwrapFlag_Pointers|E2_TypeUnwrapFlag_Bitfields))
};
internal E2_TypeKey e2_type_key_unwrap(E2_TypeKey k, E2_TypeUnwrapFlags flags);
#define e2_type_key_undecorate(k) e2_type_key_unwrap((k), E2_TypeUnwrapFlag_AllDecorative)
//- rjf: type coercion
internal E2_TypeKey e2_coerced_type_key_from_operands(E2_TypeKey lhs, E2_TypeKey rhs);
////////////////////////////////
//~ rjf: Expression Constructors
internal E2_Expr *e2_expr(Arena *arena, E2_ExprKind kind);
internal void e2_expr_push_child_node(E2_Expr *parent, E2_ExprNode *node);
internal void e2_expr_push_child(Arena *arena, E2_Expr *parent, E2_Expr *expr);
#if 0
internal E2_Expr *e2_expr_const_u64_or_smaller(Arena *arena, U64 u);
internal E2_Expr *e2_expr_const_f32(Arena *arena, F32 f32);
internal E2_Expr *e2_expr_const_f64(Arena *arena, F64 f64);
internal E2_Expr *e2_expr_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_Expr *operand);
internal E2_Expr *e2_expr_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_Expr *lhs, E2_Expr *rhs);
internal E2_Expr *e2_expr_resolve_to_value(Arena *arena, E2_Expr *expr);
internal E2_Expr *e2_expr_truncate(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key);
internal E2_Expr *e2_expr_convert_if_possible(Arena *arena, E2_Expr *expr, E2_TypeKey dst_type_key);
internal E2_Expr *e2_expr_type(Arena *arena, E2_TypeKey type_key);
#endif
////////////////////////////////
//~ rjf: IR Tree Constructors
internal E2_IRNode *e2_irnode(Arena *arena);
internal E2_IRNode *e2_irnode_const_u64_or_smaller(Arena *arena, U64 u);
internal E2_IRNode *e2_irnode_const_f32(Arena *arena, F32 f32);
internal E2_IRNode *e2_irnode_const_f64(Arena *arena, F64 f64);
internal E2_IRNode *e2_irnode_unary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *operand);
internal E2_IRNode *e2_irnode_binary_op(Arena *arena, E2_TypeKey type_key, RDI_EvalOp op, E2_IRNode *lhs, E2_IRNode *rhs);
internal E2_IRNode *e2_irnode_resolve_to_value(Arena *arena, E2_IRNode *expr);
internal E2_IRNode *e2_irnode_truncate(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key);
internal E2_IRNode *e2_irnode_convert_if_possible(Arena *arena, E2_IRNode *expr, E2_TypeKey dst_type_key);
internal E2_IRNode *e2_irnode_type(Arena *arena, E2_TypeKey type_key);
internal void e2_irnode_push_child_node(E2_IRNode *parent, E2_IRNodePtrNode *node);
internal void e2_irnode_push_child(Arena *arena, E2_IRNode *parent, E2_IRNode *expr);
////////////////////////////////
//~ rjf: String -> Expression
internal E2_Token e2_token_from_string_off(E2_LangKind lang, String8 string, U64 start_off);
internal U64 e2_read_token(E2_LangKind lang, String8 string, U64 off, E2_Token *token_out);
internal B32 e2_try_token(E2_LangKind lang, String8 string, E2_TokenKind kind, String8 expected_string, U64 *off_out, E2_Token *token_out);
internal E2_Parse e2_parse_from_string(Arena *arena, E2_ParseState *state, B32 identifier_is_type, E2_LangKind lang, String8 string);
////////////////////////////////
//~ rjf: Expression -> IR Tree
internal E2_Compile e2_compile_from_expr(Arena *arena, E2_CompileState *state, E2_IRNode *resolve_result, E2_Val compile_time_eval_result, E2_Expr *expr);
////////////////////////////////
//~ rjf: IR Tree -> Bytecode
internal String8 e2_bytecode_from_irnode(Arena *arena, E2_IRNode *irnode);
////////////////////////////////
//~ rjf: Bytecode -> Result
internal E2_Interp e2_interp_from_bytecode(Arena *arena, E2_InterpState *state, E2_SpaceMap *space_map, String8 bytecode);
#endif // EVAL2_H