mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
1299 lines
43 KiB
C++
1299 lines
43 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "zeek/script_opt/CPP/Compile.h"
|
|
|
|
namespace zeek::detail {
|
|
|
|
using namespace std;
|
|
|
|
string CPPCompile::GenExprs(const Expr* e) {
|
|
string gen;
|
|
if ( e->Tag() == EXPR_LIST )
|
|
gen = GenListExpr(e, GEN_VAL_PTR, true);
|
|
else
|
|
gen = GenExpr(e, GEN_VAL_PTR);
|
|
|
|
return string("{ ") + gen + " }";
|
|
}
|
|
|
|
string CPPCompile::GenListExpr(const Expr* e, GenType gt, bool nested) {
|
|
const auto& exprs = e->AsListExpr()->Exprs();
|
|
string gen;
|
|
|
|
int n = exprs.size();
|
|
|
|
for ( auto i = 0; i < n; ++i ) {
|
|
auto e_i = exprs[i];
|
|
auto gen_i = GenExpr(e_i, gt);
|
|
|
|
if ( nested && e_i->Tag() == EXPR_LIST )
|
|
// These are table or set indices.
|
|
gen_i = string("index_val__CPP({") + gen_i + "})";
|
|
|
|
gen += gen_i;
|
|
|
|
if ( i < n - 1 )
|
|
gen += ", ";
|
|
}
|
|
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenExpr(const Expr* e, GenType gt, bool top_level) {
|
|
string gen;
|
|
|
|
switch ( e->Tag() ) {
|
|
case EXPR_NAME: return GenNameExpr(e->AsNameExpr(), gt);
|
|
case EXPR_CONST: return GenConstExpr(e->AsConstExpr(), gt);
|
|
|
|
case EXPR_CLONE:
|
|
gen = GenExpr(e->GetOp1(), GEN_VAL_PTR) + "->Clone()";
|
|
return GenericValPtrToGT(gen, e->GetType(), gt);
|
|
|
|
case EXPR_AGGR_ADD: return GenAggrAdd(e);
|
|
case EXPR_AGGR_DEL: return GenAggrDel(e);
|
|
|
|
case EXPR_INCR:
|
|
case EXPR_DECR: return GenIncrExpr(e, gt, e->Tag() == EXPR_INCR, top_level);
|
|
|
|
case EXPR_NOT: return GenUnary(e, gt, "!", "not");
|
|
case EXPR_COMPLEMENT: return GenUnary(e, gt, "~", "comp");
|
|
case EXPR_POSITIVE: return GenUnary(e, gt, "+", "pos");
|
|
case EXPR_NEGATE: return GenUnary(e, gt, "-", "neg");
|
|
|
|
case EXPR_ADD: return GenBinary(e, gt, "+", "add");
|
|
case EXPR_SUB: return GenBinary(e, gt, "-", "sub");
|
|
case EXPR_TIMES: return GenBinary(e, gt, "*", "mul");
|
|
case EXPR_DIVIDE:
|
|
case EXPR_MASK: // later code will split into addr masking
|
|
return GenBinary(e, gt, "/", "div");
|
|
case EXPR_MOD: return GenBinary(e, gt, "%", "mod");
|
|
case EXPR_AND: return GenBinary(e, gt, "&", "and");
|
|
case EXPR_OR: return GenBinary(e, gt, "|", "or");
|
|
case EXPR_XOR: return GenBinary(e, gt, "^", "xor");
|
|
case EXPR_LSHIFT: return GenBinary(e, gt, "<<", "lshift");
|
|
case EXPR_RSHIFT: return GenBinary(e, gt, ">>", "rshift");
|
|
case EXPR_AND_AND: return GenBinary(e, gt, "&&", "andand");
|
|
case EXPR_OR_OR: return GenBinary(e, gt, "||", "oror");
|
|
case EXPR_LT: return GenBinary(e, gt, "<", "lt");
|
|
case EXPR_LE: return GenBinary(e, gt, "<=", "le");
|
|
case EXPR_GE: return GenBinary(e, gt, ">=", "ge");
|
|
case EXPR_GT: return GenBinary(e, gt, ">", "gt");
|
|
|
|
case EXPR_EQ: return GenEQ(e, gt, "==", "eq");
|
|
case EXPR_NE: return GenEQ(e, gt, "!=", "ne");
|
|
|
|
case EXPR_COND: return GenCondExpr(e, gt);
|
|
case EXPR_CALL: return GenCallExpr(e->AsCallExpr(), gt, top_level);
|
|
case EXPR_LIST: return GenListExpr(e, gt, false);
|
|
case EXPR_IN: return GenInExpr(e, gt);
|
|
case EXPR_FIELD: return GenFieldExpr(e->AsFieldExpr(), gt);
|
|
case EXPR_HAS_FIELD: return GenHasFieldExpr(e->AsHasFieldExpr(), gt);
|
|
case EXPR_INDEX: return GenIndexExpr(e, gt);
|
|
case EXPR_ASSIGN: return GenAssignExpr(e, gt, top_level);
|
|
case EXPR_ADD_TO: return GenAddToExpr(e, gt, top_level);
|
|
case EXPR_REMOVE_FROM: return GenRemoveFromExpr(e, gt, top_level);
|
|
case EXPR_REF: return GenExpr(e->GetOp1(), gt);
|
|
case EXPR_SIZE: return GenSizeExpr(e, gt);
|
|
case EXPR_SCHEDULE: return GenScheduleExpr(e);
|
|
case EXPR_LAMBDA: return GenLambdaExpr(e);
|
|
case EXPR_IS: return GenIsExpr(e, gt);
|
|
|
|
case EXPR_ARITH_COERCE: return GenArithCoerceExpr(e, gt);
|
|
case EXPR_RECORD_COERCE: return GenRecordCoerceExpr(e);
|
|
case EXPR_TABLE_COERCE: return GenTableCoerceExpr(e);
|
|
case EXPR_VECTOR_COERCE: return GenVectorCoerceExpr(e);
|
|
|
|
case EXPR_RECORD_CONSTRUCTOR: return GenRecordConstructorExpr(e);
|
|
case EXPR_SET_CONSTRUCTOR: return GenSetConstructorExpr(e);
|
|
case EXPR_TABLE_CONSTRUCTOR: return GenTableConstructorExpr(e);
|
|
case EXPR_VECTOR_CONSTRUCTOR: return GenVectorConstructorExpr(e);
|
|
|
|
case EXPR_EVENT:
|
|
// These should not wind up being directly generated,
|
|
// but instead deconstructed in the context of either
|
|
// a "schedule" expression or an "event" statement.
|
|
ASSERT(0);
|
|
|
|
case EXPR_CAST:
|
|
gen = string("cast_value_to_type__CPP(") + GenExpr(e->GetOp1(), GEN_VAL_PTR) + ", " +
|
|
GenTypeName(e->GetType()) + ")";
|
|
return GenericValPtrToGT(gen, e->GetType(), gt);
|
|
|
|
case EXPR_TO_ANY_COERCE: return GenExpr(e->GetOp1(), GEN_VAL_PTR);
|
|
|
|
case EXPR_FROM_ANY_COERCE:
|
|
gen = string("from_any__CPP(") + GenExpr(e->GetOp1(), GEN_VAL_PTR) + ", " + GenTypeName(e->GetType()) + ")";
|
|
return GenericValPtrToGT(gen, e->GetType(), gt);
|
|
|
|
case EXPR_FROM_ANY_VEC_COERCE:
|
|
gen = string("from_any_vec__CPP(") + GenExpr(e->GetOp1(), GEN_VAL_PTR) + ", " +
|
|
GenTypeName(e->GetType()->Yield()) + ")";
|
|
return GenericValPtrToGT(gen, e->GetType(), gt);
|
|
|
|
case EXPR_FIELD_ASSIGN:
|
|
case EXPR_INDEX_SLICE_ASSIGN:
|
|
case EXPR_INLINE:
|
|
// These are only generated for reduced ASTs, which
|
|
// we shouldn't be compiling.
|
|
ASSERT(0);
|
|
|
|
default:
|
|
// Intended to catch errors in overlooking the possible
|
|
// expressions that might appear.
|
|
return string("EXPR");
|
|
}
|
|
}
|
|
|
|
string CPPCompile::GenNameExpr(const NameExpr* ne, GenType gt) {
|
|
const auto& t = ne->GetType();
|
|
auto n = ne->Id();
|
|
bool is_global_var = global_vars.count(n) > 0;
|
|
|
|
if ( t->Tag() == TYPE_FUNC && ! is_global_var ) {
|
|
auto func = n->Name();
|
|
if ( globals.count(func) > 0 && pfs->BiFGlobals().count(n) == 0 )
|
|
return GenericValPtrToGT(IDNameStr(n), t, gt);
|
|
}
|
|
|
|
if ( is_global_var ) {
|
|
string gen;
|
|
|
|
if ( n->IsType() )
|
|
gen = string("make_intrusive<TypeVal>(") + globals[n->Name()] + "->GetType(), true)";
|
|
|
|
else
|
|
gen = globals[n->Name()] + "->GetVal()";
|
|
|
|
return GenericValPtrToGT(gen, t, gt);
|
|
}
|
|
|
|
return NativeToGT(IDNameStr(n), t, gt);
|
|
}
|
|
|
|
string CPPCompile::GenConstExpr(const ConstExpr* c, GenType gt) {
|
|
const auto& t = c->GetType();
|
|
|
|
if ( ! IsNativeType(t) ) {
|
|
auto v = c->ValuePtr();
|
|
int consts_offset; // ignored
|
|
(void)RegisterConstant(v, consts_offset);
|
|
return NativeToGT(const_vals[v.get()]->Name(), t, gt);
|
|
}
|
|
|
|
return NativeToGT(GenVal(c->ValuePtr()), t, gt);
|
|
}
|
|
|
|
string CPPCompile::GenAggrAdd(const Expr* e) {
|
|
auto op = e->GetOp1();
|
|
auto aggr = GenExpr(op->GetOp1(), GEN_DONT_CARE);
|
|
auto indices = GenExpr(op->GetOp2(), GEN_VAL_PTR);
|
|
|
|
return "add_element__CPP(" + aggr + ", index_val__CPP({" + indices + "}))";
|
|
}
|
|
|
|
string CPPCompile::GenAggrDel(const Expr* e) {
|
|
auto op = e->GetOp1();
|
|
|
|
if ( op->Tag() == EXPR_NAME ) {
|
|
auto aggr_gen = GenExpr(op, GEN_VAL_PTR);
|
|
|
|
if ( op->GetType()->Tag() == TYPE_TABLE )
|
|
return aggr_gen + "->RemoveAll()";
|
|
else
|
|
return aggr_gen + "->Resize(0)";
|
|
}
|
|
|
|
auto aggr = op->GetOp1();
|
|
auto aggr_gen = GenExpr(aggr, GEN_VAL_PTR);
|
|
|
|
if ( op->Tag() == EXPR_INDEX ) {
|
|
auto indices = GenExpr(op->GetOp2(), GEN_VAL_PTR);
|
|
return "remove_element__CPP(" + aggr_gen + ", index_val__CPP({" + indices + "}))";
|
|
}
|
|
|
|
ASSERT(op->Tag() == EXPR_FIELD);
|
|
auto field = GenField(aggr, op->AsFieldExpr()->Field());
|
|
return aggr_gen + "->Remove(" + field + ")";
|
|
}
|
|
|
|
string CPPCompile::GenIncrExpr(const Expr* e, GenType gt, bool is_incr, bool top_level) {
|
|
// For compound operands (table indexing, record fields),
|
|
// Zeek's interpreter will actually evaluate the operand
|
|
// twice, so easiest is to just transform this node
|
|
// into the expanded equivalent.
|
|
auto op = e->GetOp1();
|
|
auto one = e->GetType()->InternalType() == TYPE_INTERNAL_INT ? val_mgr->Int(1) : val_mgr->Count(1);
|
|
auto one_e = make_intrusive<ConstExpr>(one);
|
|
|
|
ExprPtr rhs;
|
|
if ( is_incr )
|
|
rhs = make_intrusive<AddExpr>(op, one_e);
|
|
else
|
|
rhs = make_intrusive<SubExpr>(op, one_e);
|
|
|
|
auto assign = make_intrusive<AssignExpr>(op, rhs, false, nullptr, nullptr, false);
|
|
|
|
// Make sure any newly created types are known to
|
|
// the profiler.
|
|
(void)pfs->HashType(one_e->GetType());
|
|
(void)pfs->HashType(rhs->GetType());
|
|
(void)pfs->HashType(assign->GetType());
|
|
|
|
auto gen = GenExpr(assign, GEN_DONT_CARE, top_level);
|
|
|
|
if ( ! top_level )
|
|
gen = "(" + gen + ", " + GenExpr(op, gt) + ")";
|
|
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenCondExpr(const Expr* e, GenType gt) {
|
|
auto op1 = e->GetOp1();
|
|
auto op2 = e->GetOp2();
|
|
auto op3 = e->GetOp3();
|
|
|
|
auto gen1 = GenExpr(op1, GEN_NATIVE);
|
|
auto gen2 = GenExpr(op2, gt);
|
|
auto gen3 = GenExpr(op3, gt);
|
|
|
|
if ( op1->GetType()->Tag() == TYPE_VECTOR )
|
|
return string("vector_select__CPP(") + gen1 + ", " + gen2 + ", " + gen3 + ")";
|
|
|
|
return string("(") + gen1 + ") ? (" + gen2 + ") : (" + gen3 + ")";
|
|
}
|
|
|
|
string CPPCompile::GenCallExpr(const CallExpr* c, GenType gt, bool top_level) {
|
|
const auto& t = c->GetType();
|
|
auto f = c->Func();
|
|
auto args_l = c->Args();
|
|
bool is_async = c->IsInWhen();
|
|
|
|
auto gen = GenExpr(f, GEN_DONT_CARE);
|
|
|
|
if ( f->Tag() == EXPR_NAME ) {
|
|
auto f_id = f->AsNameExpr()->Id();
|
|
const auto& params = f_id->GetType()->AsFuncType()->Params();
|
|
auto id_name = f_id->Name();
|
|
auto nargs = args_l->Exprs().length();
|
|
|
|
bool is_compiled = compiled_simple_funcs.count(id_name) > 0;
|
|
bool was_compiled = hashed_funcs.count(id_name) > 0;
|
|
bool is_variadic = params->NumFields() == 1 && nargs != 1;
|
|
|
|
if ( ! is_async && ! is_variadic && (is_compiled || was_compiled) ) { // Can call directly.
|
|
string fname;
|
|
|
|
if ( was_compiled )
|
|
fname = hashed_funcs[id_name];
|
|
else
|
|
fname = compiled_simple_funcs[id_name];
|
|
|
|
if ( nargs > 0 )
|
|
gen = fname + "(" + GenArgs(params, args_l) + ", f__CPP)";
|
|
else
|
|
gen = fname + "(f__CPP)";
|
|
|
|
return NativeToGT(gen, t, gt);
|
|
}
|
|
|
|
// If the function isn't a BiF, then it will have been
|
|
// declared as a ValPtr (or a FuncValPtr, if a local),
|
|
// and we need to convert it to a Func*.
|
|
//
|
|
// If it is a BiF *that's also a global variable*, then
|
|
// we need to look up the BiF version of the global.
|
|
if ( pfs->BiFGlobals().count(f_id) == 0 )
|
|
gen += +"->AsFunc()";
|
|
|
|
else if ( accessed_globals.count(f_id) > 0 )
|
|
// The BiF version has an extra "_", per AddBiF(..., true).
|
|
gen = globals[string(id_name) + "_"];
|
|
}
|
|
|
|
else
|
|
// Indirect call.
|
|
gen = string("(") + gen + ")->AsFunc()";
|
|
|
|
string invoke_func;
|
|
|
|
if ( is_async )
|
|
invoke_func = "when_invoke__CPP";
|
|
else if ( top_level || t->Tag() == TYPE_VOID ) {
|
|
ASSERT(top_level);
|
|
invoke_func = "invoke_void__CPP";
|
|
}
|
|
else
|
|
invoke_func = "invoke__CPP";
|
|
|
|
auto args_list = string(", {") + GenExpr(args_l, GEN_VAL_PTR) + "}";
|
|
auto invoker = invoke_func + "(" + gen + args_list + ", f__CPP";
|
|
|
|
if ( is_async )
|
|
invoker += ", (void*) &" + body_name;
|
|
|
|
invoker += ")";
|
|
|
|
if ( top_level )
|
|
// No need to use accessor.
|
|
return invoker;
|
|
|
|
if ( IsNativeType(t) && gt != GEN_VAL_PTR )
|
|
return invoker + NativeAccessor(t);
|
|
|
|
return GenericValPtrToGT(invoker, t, gt);
|
|
}
|
|
|
|
string CPPCompile::GenInExpr(const Expr* e, GenType gt) {
|
|
auto op1 = e->GetOp1();
|
|
auto op2 = e->GetOp2();
|
|
|
|
auto t1 = op1->GetType();
|
|
auto t2 = op2->GetType();
|
|
|
|
auto tag1 = t1->Tag();
|
|
auto tag2 = t2->Tag();
|
|
|
|
string gen;
|
|
|
|
if ( tag1 == TYPE_STRING && tag2 == TYPE_TABLE && t2->AsTableType()->IsPatternIndex() )
|
|
gen = GenExpr(op2, GEN_DONT_CARE) + "->MatchPattern(" + GenExpr(op1, GEN_NATIVE) + ")";
|
|
else if ( tag1 == TYPE_PATTERN )
|
|
gen = string("(") + GenExpr(op1, GEN_DONT_CARE) + ")->MatchAnywhere(" + GenExpr(op2, GEN_DONT_CARE) +
|
|
"->AsString())";
|
|
|
|
else if ( tag2 == TYPE_STRING )
|
|
gen = string("str_in__CPP(") + GenExpr(op1, GEN_DONT_CARE) + "->AsString(), " + GenExpr(op2, GEN_DONT_CARE) +
|
|
"->AsString())";
|
|
|
|
else if ( tag1 == TYPE_ADDR && tag2 == TYPE_SUBNET )
|
|
gen = string("(") + GenExpr(op2, GEN_DONT_CARE) + ")->Contains(" + GenExpr(op1, GEN_VAL_PTR) + "->Get())";
|
|
|
|
else if ( tag2 == TYPE_VECTOR )
|
|
gen = GenExpr(op2, GEN_DONT_CARE) + "->Has(" + GenExpr(op1, GEN_NATIVE) + ")";
|
|
|
|
else
|
|
gen = string("(") + GenExpr(op2, GEN_DONT_CARE) + "->Find(index_val__CPP({" + GenExpr(op1, GEN_VAL_PTR) +
|
|
"})) ? true : false)";
|
|
|
|
return NativeToGT(gen, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenFieldExpr(const FieldExpr* fe, GenType gt) {
|
|
auto& t = fe->GetType();
|
|
auto r = fe->GetOp1();
|
|
auto f = fe->Field();
|
|
auto f_s = GenField(r, f);
|
|
|
|
string gen;
|
|
|
|
if ( IsNativeType(t) ) {
|
|
auto nt = TypeName(t);
|
|
gen = string("field_access_") + nt + "__CPP(" + GenExpr(r, GEN_VAL_PTR) + ", " + f_s + ")";
|
|
return NativeToGT(gen, t, gt);
|
|
}
|
|
|
|
switch ( t->Tag() ) {
|
|
case TYPE_FILE:
|
|
case TYPE_FUNC:
|
|
case TYPE_VOID:
|
|
gen = string("field_access__CPP(") + GenExpr(r, GEN_VAL_PTR) + ", " + f_s + ")";
|
|
return GenericValPtrToGT(gen, t, gt);
|
|
|
|
default: {
|
|
auto nt = TypeName(t);
|
|
return string("field_access_") + nt + "__CPP(" + GenExpr(r, GEN_VAL_PTR) + ", " + f_s + ")";
|
|
}
|
|
}
|
|
}
|
|
|
|
string CPPCompile::GenHasFieldExpr(const HasFieldExpr* hfe, GenType gt) {
|
|
auto r = hfe->GetOp1();
|
|
auto f = hfe->Field();
|
|
auto f_s = GenField(r, f);
|
|
|
|
auto gen = GenExpr(r, GEN_DONT_CARE) + "->HasField(" + f_s + ")";
|
|
|
|
return NativeToGT(gen, hfe->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenIndexExpr(const Expr* e, GenType gt) {
|
|
auto aggr = e->GetOp1();
|
|
const auto& aggr_t = aggr->GetType();
|
|
bool inside_when = e->AsIndexExpr()->IsInsideWhen();
|
|
|
|
string gen;
|
|
string func;
|
|
|
|
if ( aggr_t->Tag() == TYPE_TABLE ) {
|
|
auto ind_expr = e->GetOp2()->AsListExpr()->Exprs()[0];
|
|
auto is_pat_str_ind = false;
|
|
|
|
if ( aggr_t->AsTableType()->IsPatternIndex() && ind_expr->GetType()->Tag() == TYPE_STRING )
|
|
is_pat_str_ind = true;
|
|
|
|
if ( inside_when ) {
|
|
if ( is_pat_str_ind )
|
|
func = "when_index_patstr__CPP";
|
|
else
|
|
func = "when_index_table__CPP";
|
|
}
|
|
else {
|
|
if ( is_pat_str_ind )
|
|
func = "index_patstr_table__CPP";
|
|
else
|
|
func = "index_table__CPP";
|
|
}
|
|
|
|
gen = func + "(" + GenExpr(aggr, GEN_NATIVE) + ", {" + GenExpr(e->GetOp2(), GEN_VAL_PTR) + "})";
|
|
}
|
|
|
|
else if ( aggr_t->Tag() == TYPE_VECTOR ) {
|
|
const auto& op2 = e->GetOp2();
|
|
const auto& t2 = op2->GetType();
|
|
ASSERT(t2->Tag() == TYPE_LIST);
|
|
|
|
if ( t2->Tag() == TYPE_LIST && t2->AsTypeList()->GetTypes().size() == 2 ) {
|
|
auto& inds = op2->AsListExpr()->Exprs();
|
|
auto first = inds[0];
|
|
auto last = inds[1];
|
|
func = inside_when ? "when_index_slice__CPP" : "index_slice";
|
|
gen = func + "(" + GenExpr(aggr, GEN_VAL_PTR) + ".get(), " + GenExpr(first, GEN_NATIVE) + ", " +
|
|
GenExpr(last, GEN_NATIVE) + ")";
|
|
}
|
|
else {
|
|
func = inside_when ? "when_index_vec__CPP" : "index_vec__CPP";
|
|
gen = func + "(" + GenExpr(aggr, GEN_NATIVE) + ", " + GenExpr(e->GetOp2(), GEN_NATIVE) + ")";
|
|
}
|
|
}
|
|
|
|
else if ( aggr_t->Tag() == TYPE_STRING )
|
|
gen =
|
|
string("index_string__CPP(") + GenExpr(aggr, GEN_NATIVE) + ", {" + GenExpr(e->GetOp2(), GEN_VAL_PTR) + "})";
|
|
|
|
return GenericValPtrToGT(gen, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenAssignExpr(const Expr* e, GenType gt, bool top_level) {
|
|
auto op1 = e->GetOp1()->AsRefExprPtr()->GetOp1();
|
|
auto op2 = e->GetOp2();
|
|
|
|
const auto& t1 = op1->GetType();
|
|
const auto& t2 = op2->GetType();
|
|
|
|
auto rhs_native = GenExpr(op2, GEN_NATIVE);
|
|
auto rhs_val_ptr = GenExpr(op2, GEN_VAL_PTR);
|
|
|
|
auto lhs_is_any = t1->Tag() == TYPE_ANY;
|
|
auto rhs_is_any = t2->Tag() == TYPE_ANY;
|
|
|
|
if ( lhs_is_any && ! rhs_is_any )
|
|
rhs_native = rhs_val_ptr;
|
|
|
|
if ( rhs_is_any && ! lhs_is_any && t1->Tag() != TYPE_LIST )
|
|
rhs_native = rhs_val_ptr = GenericValPtrToGT(rhs_val_ptr, t1, GEN_NATIVE);
|
|
|
|
auto gen = GenAssign(op1, op2, rhs_native, rhs_val_ptr, gt, top_level);
|
|
auto av = e->AsAssignExpr()->AssignVal();
|
|
if ( av ) {
|
|
auto av_e = make_intrusive<ConstExpr>(av);
|
|
auto av_gen = GenExpr(av_e, gt, false);
|
|
return string("(") + gen + ", " + av_gen + ")";
|
|
}
|
|
else
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenAddToExpr(const Expr* e, GenType gt, bool top_level) {
|
|
const auto& t = e->GetType();
|
|
auto lhs = e->GetOp1();
|
|
auto rhs = e->GetOp2();
|
|
|
|
std::string add_to_func;
|
|
|
|
if ( t->Tag() == TYPE_VECTOR ) {
|
|
auto& rt = rhs->GetType();
|
|
|
|
ASSERT(e->Tag() == EXPR_ADD_TO);
|
|
if ( static_cast<const AddToExpr*>(e)->IsVectorElemAppend() )
|
|
add_to_func = "vector_append__CPP";
|
|
else
|
|
add_to_func = "vector_vec_append__CPP";
|
|
}
|
|
|
|
else if ( t->Tag() == TYPE_PATTERN )
|
|
add_to_func = "re_append__CPP";
|
|
|
|
else if ( t->Tag() == TYPE_TABLE )
|
|
add_to_func = "table_append__CPP";
|
|
|
|
if ( ! add_to_func.empty() ) {
|
|
auto gen = add_to_func + "(" + GenExpr(lhs, GEN_VAL_PTR) + ", " + GenExpr(rhs, GEN_VAL_PTR) + ")";
|
|
return GenericValPtrToGT(gen, t, gt);
|
|
}
|
|
|
|
// Second GetOp1 is because if we get this far, LHS will be a RefExpr.
|
|
lhs = lhs->GetOp1();
|
|
|
|
if ( t->Tag() == TYPE_STRING ) {
|
|
auto rhs_native = GenBinaryString(e, GEN_NATIVE, "+=");
|
|
auto rhs_val_ptr = GenBinaryString(e, GEN_VAL_PTR, "+=");
|
|
|
|
return GenAssign(lhs, nullptr, rhs_native, rhs_val_ptr, gt, top_level);
|
|
}
|
|
|
|
if ( lhs->Tag() != EXPR_NAME || lhs->AsNameExpr()->Id()->IsGlobal() ) {
|
|
// LHS is a compound, or a global (and thus doesn't
|
|
// equate to a C++ variable); expand x += y to x = x + y
|
|
rhs = make_intrusive<AddExpr>(lhs, rhs);
|
|
auto assign = make_intrusive<AssignExpr>(lhs, rhs, false, nullptr, nullptr, false);
|
|
|
|
// Make sure any newly created types are known to
|
|
// the profiler.
|
|
(void)pfs->HashType(rhs->GetType());
|
|
(void)pfs->HashType(assign->GetType());
|
|
|
|
return GenExpr(assign, gt, top_level);
|
|
}
|
|
|
|
return GenBinary(e, gt, "+=");
|
|
}
|
|
|
|
string CPPCompile::GenRemoveFromExpr(const Expr* e, GenType gt, bool top_level) {
|
|
const auto& t = e->GetType();
|
|
auto lhs = e->GetOp1();
|
|
auto rhs = e->GetOp2();
|
|
|
|
if ( t->Tag() == TYPE_TABLE && same_type(lhs->GetType(), rhs->GetType()) ) {
|
|
auto gen =
|
|
std::string("table_remove_from__CPP(") + GenExpr(lhs, GEN_VAL_PTR) + ", " + GenExpr(rhs, GEN_VAL_PTR) + ")";
|
|
return GenericValPtrToGT(gen, t, gt);
|
|
}
|
|
|
|
// Second GetOp1 is because if we get this far, LHS will be a RefExpr.
|
|
lhs = lhs->GetOp1();
|
|
|
|
if ( lhs->Tag() != EXPR_NAME || lhs->AsNameExpr()->Id()->IsGlobal() ) {
|
|
// LHS is a compound, or a global (and thus doesn't
|
|
// equate to a C++ variable); expand x -= y to x = x - y
|
|
rhs = make_intrusive<SubExpr>(lhs, rhs);
|
|
auto assign = make_intrusive<AssignExpr>(lhs, rhs, false, nullptr, nullptr, false);
|
|
|
|
// Make sure any newly created types are known to
|
|
// the profiler.
|
|
(void)pfs->HashType(rhs->GetType());
|
|
(void)pfs->HashType(assign->GetType());
|
|
|
|
return GenExpr(assign, gt, top_level);
|
|
}
|
|
|
|
return GenBinary(e, gt, "-=");
|
|
}
|
|
|
|
string CPPCompile::GenSizeExpr(const Expr* e, GenType gt) {
|
|
const auto& t = e->GetType();
|
|
const auto& t1 = e->GetOp1()->GetType();
|
|
auto it = t1->InternalType();
|
|
|
|
auto gen = GenExpr(e->GetOp1(), GEN_NATIVE);
|
|
|
|
if ( t1->Tag() == TYPE_BOOL )
|
|
gen = string("((") + gen + ") ? 1 : 0)";
|
|
|
|
else if ( it == TYPE_INTERNAL_UNSIGNED )
|
|
// no-op
|
|
;
|
|
|
|
else if ( it == TYPE_INTERNAL_INT )
|
|
gen = string("iabs__CPP(") + gen + ")";
|
|
|
|
else if ( it == TYPE_INTERNAL_DOUBLE )
|
|
gen = string("fabs__CPP(") + gen + ")";
|
|
|
|
else if ( gt == GEN_NATIVE && (t1->Tag() == TYPE_TABLE || t1->Tag() == TYPE_VECTOR) )
|
|
return gen + "->Size()";
|
|
|
|
else
|
|
return GenericValPtrToGT(gen + "->SizeVal()", t, gt);
|
|
|
|
return NativeToGT(gen, t, gt);
|
|
}
|
|
|
|
string CPPCompile::GenScheduleExpr(const Expr* e) {
|
|
auto s = static_cast<const ScheduleExpr*>(e);
|
|
auto when = s->When();
|
|
auto event = s->Event();
|
|
string event_name(event->Handler()->Name());
|
|
|
|
RegisterEvent(event_name);
|
|
|
|
string when_s = GenExpr(when, GEN_NATIVE);
|
|
if ( when->GetType()->Tag() == TYPE_INTERVAL )
|
|
when_s += " + run_state::network_time";
|
|
|
|
return string("schedule__CPP(") + when_s + ", " + globals[event_name] + "_ev, { " +
|
|
GenExpr(event->Args(), GEN_VAL_PTR) + " })";
|
|
}
|
|
|
|
string CPPCompile::GenLambdaExpr(const Expr* e) {
|
|
auto l = static_cast<const LambdaExpr*>(e);
|
|
auto& body = l->Ingredients()->Body();
|
|
return GenLambdaExpr(e, GenLambdaClone(l, false));
|
|
}
|
|
|
|
string CPPCompile::GenLambdaExpr(const Expr* e, string capture_args) {
|
|
auto l = static_cast<const LambdaExpr*>(e);
|
|
auto name = Canonicalize(l->Name()) + "_lb_cl";
|
|
auto cl_args = string("\"") + name + "\"" + std::move(capture_args);
|
|
auto body = string("make_intrusive<") + name + ">(" + cl_args + ")";
|
|
auto func = string("make_intrusive<CPPLambdaFunc>(\"") + l->Name() + "\", cast_intrusive<FuncType>(" +
|
|
GenTypeName(l->GetType()) + "), " + body + ")";
|
|
return string("make_intrusive<FuncVal>(") + func + ")";
|
|
}
|
|
|
|
string CPPCompile::GenIsExpr(const Expr* e, GenType gt) {
|
|
auto ie = static_cast<const IsExpr*>(e);
|
|
auto gen = string("can_cast_value_to_type(") + GenExpr(ie->GetOp1(), GEN_VAL_PTR) + ".get(), " +
|
|
GenTypeName(ie->TestType()) + ".get())";
|
|
|
|
return NativeToGT(gen, ie->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenArithCoerceExpr(const Expr* e, GenType gt) {
|
|
const auto& t = e->GetType();
|
|
auto op = e->GetOp1();
|
|
|
|
if ( same_type(t, op->GetType()) )
|
|
return GenExpr(op, gt);
|
|
|
|
if ( t->Tag() == TYPE_VECTOR )
|
|
return string("vector_coerce_to__CPP(") + GenExpr(op, GEN_NATIVE) + ", " + GenTypeName(t) + ")";
|
|
|
|
string cast_name;
|
|
|
|
switch ( t->InternalType() ) {
|
|
case TYPE_INTERNAL_INT: cast_name = "zeek_int_t"; break;
|
|
case TYPE_INTERNAL_UNSIGNED: cast_name = "zeek_uint_t"; break;
|
|
case TYPE_INTERNAL_DOUBLE: cast_name = "double"; break;
|
|
|
|
default: reporter->InternalError("bad type in arithmetic coercion");
|
|
}
|
|
|
|
return NativeToGT(cast_name + "(" + GenExpr(op, GEN_NATIVE) + ")", t, gt);
|
|
}
|
|
|
|
string CPPCompile::GenRecordCoerceExpr(const Expr* e) {
|
|
auto rc = static_cast<const RecordCoerceExpr*>(e);
|
|
auto op1 = rc->GetOp1();
|
|
const auto& from_type = op1->GetType();
|
|
const auto& to_type = rc->GetType();
|
|
|
|
if ( same_type(from_type, to_type) )
|
|
// Elide coercion.
|
|
return GenExpr(op1, GEN_VAL_PTR);
|
|
|
|
const auto& map = rc->Map();
|
|
auto type_var = GenTypeName(to_type);
|
|
|
|
return string("coerce_to_record(cast_intrusive<RecordType>(") + type_var + "), " + GenExpr(op1, GEN_VAL_PTR) +
|
|
".get(), " + GenIntVector(map) + ")";
|
|
}
|
|
|
|
string CPPCompile::GenTableCoerceExpr(const Expr* e) {
|
|
auto tc = static_cast<const TableCoerceExpr*>(e);
|
|
const auto& t = tc->GetType();
|
|
auto op1 = tc->GetOp1();
|
|
|
|
return string("table_coerce__CPP(") + GenExpr(op1, GEN_VAL_PTR) + ", " + GenTypeName(t) + ")";
|
|
}
|
|
|
|
string CPPCompile::GenVectorCoerceExpr(const Expr* e) {
|
|
auto vc = static_cast<const VectorCoerceExpr*>(e);
|
|
const auto& op = vc->GetOp1();
|
|
const auto& t = vc->GetType<VectorType>();
|
|
|
|
return string("vector_coerce__CPP(" + GenExpr(op, GEN_VAL_PTR) + ", " + GenTypeName(t) + ")");
|
|
}
|
|
|
|
string CPPCompile::GenRecordConstructorExpr(const Expr* e) {
|
|
auto rc = static_cast<const RecordConstructorExpr*>(e);
|
|
const auto& t = rc->GetType();
|
|
const auto& exprs = rc->Op()->AsListExpr()->Exprs();
|
|
auto n = exprs.length();
|
|
|
|
string vals;
|
|
|
|
for ( auto i = 0; i < n; ++i ) {
|
|
const auto& expr = exprs[i];
|
|
|
|
ASSERT(expr->Tag() == EXPR_FIELD_ASSIGN);
|
|
|
|
vals += GenExpr(expr->GetOp1(), GEN_VAL_PTR);
|
|
|
|
if ( i < n - 1 )
|
|
vals += ", ";
|
|
}
|
|
|
|
vals = string("{") + vals + "}";
|
|
|
|
const auto& map = rc->Map();
|
|
|
|
if ( map ) {
|
|
string map_vals;
|
|
for ( auto m : *map ) {
|
|
if ( ! map_vals.empty() )
|
|
map_vals += ", ";
|
|
|
|
map_vals += to_string(m);
|
|
}
|
|
|
|
map_vals = string("{") + map_vals + "}";
|
|
|
|
return string("record_constructor_map__CPP(") + vals + ", " + map_vals + ", cast_intrusive<RecordType>(" +
|
|
GenTypeName(t) + "))";
|
|
}
|
|
|
|
else
|
|
return string("record_constructor__CPP(") + vals + ", cast_intrusive<RecordType>(" + GenTypeName(t) + "))";
|
|
}
|
|
|
|
string CPPCompile::GenSetConstructorExpr(const Expr* e) {
|
|
auto sc = static_cast<const SetConstructorExpr*>(e);
|
|
const auto& t = sc->GetType();
|
|
const auto& attrs = sc->GetAttrs();
|
|
|
|
string attr_tags;
|
|
string attr_vals;
|
|
BuildAttrs(attrs, attr_tags, attr_vals);
|
|
|
|
return string("set_constructor__CPP(") + GenExprs(sc->GetOp1().get()) + ", " + "cast_intrusive<TableType>(" +
|
|
GenTypeName(t) + "), " + attr_tags + ", " + attr_vals + ")";
|
|
}
|
|
|
|
string CPPCompile::GenTableConstructorExpr(const Expr* e) {
|
|
auto tc = static_cast<const TableConstructorExpr*>(e);
|
|
const auto& t = tc->GetType();
|
|
const auto& attrs = tc->GetAttrs();
|
|
|
|
string attr_tags;
|
|
string attr_vals;
|
|
BuildAttrs(attrs, attr_tags, attr_vals);
|
|
|
|
string indices;
|
|
string vals;
|
|
|
|
const auto& exprs = tc->GetOp1()->AsListExpr()->Exprs();
|
|
auto n = exprs.length();
|
|
|
|
for ( auto i = 0; i < n; ++i ) {
|
|
const auto& expr = exprs[i];
|
|
|
|
ASSERT(expr->Tag() == EXPR_ASSIGN);
|
|
|
|
auto index = expr->GetOp1();
|
|
auto v = expr->GetOp2();
|
|
|
|
if ( index->Tag() == EXPR_LIST )
|
|
// Multiple indices.
|
|
indices += "index_val__CPP({" + GenExpr(index, GEN_VAL_PTR) + "})";
|
|
else
|
|
indices += GenExpr(index, GEN_VAL_PTR);
|
|
|
|
vals += GenExpr(v, GEN_VAL_PTR);
|
|
|
|
if ( i < n - 1 ) {
|
|
indices += ", ";
|
|
vals += ", ";
|
|
}
|
|
}
|
|
|
|
return string("table_constructor__CPP({") + indices + "}, {" + vals + "}, " + "cast_intrusive<TableType>(" +
|
|
GenTypeName(t) + "), " + attr_tags + ", " + attr_vals + ")";
|
|
}
|
|
|
|
string CPPCompile::GenVectorConstructorExpr(const Expr* e) {
|
|
auto vc = static_cast<const VectorConstructorExpr*>(e);
|
|
const auto& t = vc->GetType();
|
|
|
|
return string("vector_constructor__CPP({") + GenExpr(vc->GetOp1(), GEN_VAL_PTR) + "}, " +
|
|
"cast_intrusive<VectorType>(" + GenTypeName(t) + "))";
|
|
}
|
|
|
|
string CPPCompile::GenVal(const ValPtr& v) {
|
|
const auto& t = v->GetType();
|
|
auto tag = t->Tag();
|
|
auto it = t->InternalType();
|
|
|
|
if ( tag == TYPE_BOOL )
|
|
return string(v->IsZero() ? "false" : "true");
|
|
|
|
if ( tag == TYPE_ENUM )
|
|
return GenEnum(t, v);
|
|
|
|
if ( tag == TYPE_PORT )
|
|
return Fmt(int(v->AsCount()));
|
|
|
|
if ( it == TYPE_INTERNAL_DOUBLE )
|
|
return Fmt(v->AsDouble());
|
|
|
|
ODesc d;
|
|
d.SetQuotes(true);
|
|
v->Describe(&d);
|
|
return d.Description();
|
|
}
|
|
|
|
string CPPCompile::GenUnary(const Expr* e, GenType gt, const char* op, const char* vec_op) {
|
|
if ( e->GetType()->Tag() == TYPE_VECTOR )
|
|
return GenVectorOp(e, GenExpr(e->GetOp1(), GEN_NATIVE), vec_op);
|
|
|
|
// Look for coercions that the interpreter does implicitly.
|
|
auto op1 = e->GetOp1();
|
|
if ( op1->GetType()->Tag() == TYPE_COUNT && (e->Tag() == EXPR_POSITIVE || e->Tag() == EXPR_NEGATE) )
|
|
op1 = make_intrusive<ArithCoerceExpr>(op1, TYPE_INT);
|
|
|
|
return NativeToGT(string(op) + "(" + GenExpr(op1, GEN_NATIVE) + ")", e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenBinary(const Expr* e, GenType gt, const char* op, const char* vec_op) {
|
|
const auto& op1 = e->GetOp1();
|
|
const auto& op2 = e->GetOp2();
|
|
auto t = op1->GetType();
|
|
|
|
if ( e->GetType()->Tag() == TYPE_VECTOR ) {
|
|
auto gen1 = GenExpr(op1, GEN_NATIVE);
|
|
auto gen2 = GenExpr(op2, GEN_NATIVE);
|
|
|
|
if ( t->Tag() == TYPE_VECTOR && t->Yield()->Tag() == TYPE_STRING && op2->GetType()->Tag() == TYPE_VECTOR )
|
|
return string("str_vec_op_") + vec_op + "__CPP(" + gen1 + ", " + gen2 + ")";
|
|
|
|
return GenVectorOp(e, gen1, gen2, vec_op);
|
|
}
|
|
|
|
if ( t->IsSet() )
|
|
return GenBinarySet(e, gt, op);
|
|
|
|
// The following is only used for internal int/uint/double
|
|
// operations. For those, it holds the prefix we use to
|
|
// distinguish different instances of inlined functions
|
|
// employed to support an operation.
|
|
string flavor;
|
|
|
|
switch ( t->InternalType() ) {
|
|
case TYPE_INTERNAL_INT: flavor = "i"; break;
|
|
case TYPE_INTERNAL_UNSIGNED: flavor = "u"; break;
|
|
case TYPE_INTERNAL_DOUBLE: flavor = "f"; break;
|
|
|
|
case TYPE_INTERNAL_STRING: return GenBinaryString(e, gt, op);
|
|
case TYPE_INTERNAL_ADDR: return GenBinaryAddr(e, gt, op);
|
|
case TYPE_INTERNAL_SUBNET: return GenBinarySubNet(e, gt, op);
|
|
|
|
default:
|
|
if ( t->Tag() == TYPE_PATTERN )
|
|
return GenBinaryPattern(e, gt, op);
|
|
break;
|
|
}
|
|
|
|
auto g1 = GenExpr(e->GetOp1(), GEN_NATIVE);
|
|
auto g2 = GenExpr(e->GetOp2(), GEN_NATIVE);
|
|
|
|
string gen;
|
|
|
|
if ( e->Tag() == EXPR_DIVIDE )
|
|
gen = flavor + "div__CPP(" + g1 + ", " + g2 + ")";
|
|
|
|
else if ( e->Tag() == EXPR_MOD )
|
|
gen = flavor + "mod__CPP(" + g1 + ", " + g2 + ")";
|
|
|
|
else
|
|
gen = string("(") + g1 + ")" + op + "(" + g2 + ")";
|
|
|
|
return NativeToGT(gen, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenBinarySet(const Expr* e, GenType gt, const char* op) {
|
|
auto v1 = GenExpr(e->GetOp1(), GEN_DONT_CARE) + "->AsTableVal()";
|
|
auto v2 = GenExpr(e->GetOp2(), GEN_DONT_CARE) + "->AsTableVal()";
|
|
|
|
string res;
|
|
|
|
switch ( e->Tag() ) {
|
|
case EXPR_AND: res = v1 + "->Intersection(*" + v2 + ")"; break;
|
|
|
|
case EXPR_OR: res = v1 + "->Union(" + v2 + ")"; break;
|
|
|
|
case EXPR_SUB: res = v1 + "->TakeOut(" + v2 + ")"; break;
|
|
|
|
case EXPR_EQ: res = v1 + "->EqualTo(*" + v2 + ")"; break;
|
|
|
|
case EXPR_NE: res = string("! ") + v1 + "->EqualTo(*" + v2 + ")"; break;
|
|
|
|
case EXPR_LE: res = v1 + "->IsSubsetOf(*" + v2 + ")"; break;
|
|
|
|
case EXPR_LT:
|
|
res = string("(") + v1 + "->IsSubsetOf(*" + v2 + ") &&" + v1 + "->Size() < " + v2 + "->Size())";
|
|
break;
|
|
|
|
default: reporter->InternalError("bad type in CPPCompile::GenBinarySet");
|
|
}
|
|
|
|
return NativeToGT(res, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenBinaryString(const Expr* e, GenType gt, const char* op) {
|
|
auto v1 = GenExpr(e->GetOp1(), GEN_DONT_CARE) + "->AsString()";
|
|
auto v2 = GenExpr(e->GetOp2(), GEN_DONT_CARE) + "->AsString()";
|
|
|
|
string res;
|
|
|
|
if ( e->Tag() == EXPR_ADD || e->Tag() == EXPR_ADD_TO )
|
|
res = string("str_concat__CPP(") + v1 + ", " + v2 + ")";
|
|
else
|
|
res = string("(Bstr_cmp(") + v1 + ", " + v2 + ") " + op + " 0)";
|
|
|
|
return NativeToGT(res, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenBinaryPattern(const Expr* e, GenType gt, const char* op) {
|
|
auto v1 = GenExpr(e->GetOp1(), GEN_DONT_CARE) + "->AsPattern()";
|
|
auto v2 = GenExpr(e->GetOp2(), GEN_DONT_CARE) + "->AsPattern()";
|
|
|
|
auto func = e->Tag() == EXPR_AND ? "RE_Matcher_conjunction" : "RE_Matcher_disjunction";
|
|
|
|
return NativeToGT(string("make_intrusive<PatternVal>(") + func + "(" + v1 + ", " + v2 + "))", e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenBinaryAddr(const Expr* e, GenType gt, const char* op) {
|
|
auto v1 = GenExpr(e->GetOp1(), GEN_DONT_CARE) + "->AsAddr()";
|
|
|
|
if ( e->Tag() == EXPR_MASK ) {
|
|
auto gen = string("addr_mask__CPP(") + v1 + ", " + GenExpr(e->GetOp2(), GEN_NATIVE) + ")";
|
|
|
|
return NativeToGT(gen, e->GetType(), gt);
|
|
}
|
|
|
|
auto v2 = GenExpr(e->GetOp2(), GEN_DONT_CARE) + "->AsAddr()";
|
|
|
|
return NativeToGT(v1 + op + v2, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenBinarySubNet(const Expr* e, GenType gt, const char* op) {
|
|
auto v1 = GenExpr(e->GetOp1(), GEN_DONT_CARE) + "->AsSubNet()";
|
|
auto v2 = GenExpr(e->GetOp2(), GEN_DONT_CARE) + "->AsSubNet()";
|
|
|
|
return NativeToGT(v1 + op + v2, e->GetType(), gt);
|
|
}
|
|
|
|
string CPPCompile::GenEQ(const Expr* e, GenType gt, const char* op, const char* vec_op) {
|
|
auto op1 = e->GetOp1();
|
|
auto op2 = e->GetOp2();
|
|
|
|
if ( e->GetType()->Tag() == TYPE_VECTOR ) {
|
|
auto gen1 = GenExpr(op1, GEN_NATIVE);
|
|
auto gen2 = GenExpr(op2, GEN_NATIVE);
|
|
return GenVectorOp(e, gen1, gen2, vec_op);
|
|
}
|
|
|
|
auto tag = op1->GetType()->Tag();
|
|
string negated(e->Tag() == EXPR_EQ ? "" : "! ");
|
|
|
|
if ( tag == TYPE_PATTERN ) {
|
|
auto gen1 = GenExpr(op1, GEN_DONT_CARE);
|
|
auto gen2 = GenExpr(op2, GEN_DONT_CARE);
|
|
string gen;
|
|
|
|
if ( op2->GetType()->Tag() == TYPE_PATTERN ) {
|
|
gen1 += "->AsPattern()->PatternText()";
|
|
gen2 += "->AsPattern()->PatternText()";
|
|
|
|
gen = "(strcmp(" + gen1 + ", " + gen2 + ") == 0)";
|
|
}
|
|
|
|
else
|
|
gen = gen1 + "->MatchExactly(" + gen2 + "->AsString())";
|
|
|
|
return NativeToGT(negated + gen, e->GetType(), gt);
|
|
}
|
|
|
|
if ( tag == TYPE_FUNC ) {
|
|
auto gen_f1 = GenExpr(op1, GEN_DONT_CARE);
|
|
auto gen_f2 = GenExpr(op2, GEN_DONT_CARE);
|
|
|
|
gen_f1 += "->AsFunc()";
|
|
gen_f2 += "->AsFunc()";
|
|
|
|
auto gen = string("(") + gen_f1 + "==" + gen_f2 + ")";
|
|
|
|
return NativeToGT(negated + gen, e->GetType(), gt);
|
|
}
|
|
|
|
return GenBinary(e, gt, op, vec_op);
|
|
}
|
|
|
|
string CPPCompile::GenAssign(const ExprPtr& lhs, const ExprPtr& rhs, const string& rhs_native,
|
|
const string& rhs_val_ptr, GenType gt, bool top_level) {
|
|
switch ( lhs->Tag() ) {
|
|
case EXPR_NAME: return GenDirectAssign(lhs, rhs_native, rhs_val_ptr, gt, top_level);
|
|
|
|
case EXPR_INDEX: return GenIndexAssign(lhs, rhs, rhs_val_ptr, gt, top_level);
|
|
|
|
case EXPR_FIELD: return GenFieldAssign(lhs, rhs, rhs_native, rhs_val_ptr, gt, top_level);
|
|
|
|
case EXPR_LIST: return GenListAssign(lhs, rhs);
|
|
|
|
default: reporter->InternalError("bad assignment node in CPPCompile::GenExpr"); return "XXX";
|
|
}
|
|
}
|
|
|
|
string CPPCompile::GenDirectAssign(const ExprPtr& lhs, const string& rhs_native, const string& rhs_val_ptr, GenType gt,
|
|
bool top_level) {
|
|
auto n = lhs->AsNameExpr()->Id();
|
|
|
|
if ( n->IsBlank() )
|
|
return rhs_native;
|
|
|
|
const auto& name = IDNameStr(n);
|
|
|
|
string gen;
|
|
|
|
if ( n->IsGlobal() ) {
|
|
const auto& t = n->GetType();
|
|
const auto& gn = globals[n->Name()];
|
|
|
|
if ( t->Tag() == TYPE_FUNC && t->AsFuncType()->Flavor() == FUNC_FLAVOR_EVENT ) {
|
|
gen = string("set_event__CPP(") + gn + ", " + rhs_val_ptr + ", " + gn + "_ev)";
|
|
|
|
if ( ! top_level )
|
|
gen = GenericValPtrToGT(gen, n->GetType(), gt);
|
|
}
|
|
|
|
else if ( top_level )
|
|
gen = gn + "->SetVal(" + rhs_val_ptr + ")";
|
|
|
|
else {
|
|
gen = string("set_global__CPP(") + gn + ", " + rhs_val_ptr + ")";
|
|
gen = GenericValPtrToGT(gen, n->GetType(), gt);
|
|
}
|
|
}
|
|
else {
|
|
gen = name + " = " + rhs_native;
|
|
if ( ! top_level )
|
|
gen = NativeToGT("(" + gen + ")", n->GetType(), gt);
|
|
}
|
|
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenIndexAssign(const ExprPtr& lhs, const ExprPtr& rhs, const string& rhs_val_ptr, GenType gt,
|
|
bool top_level) {
|
|
auto gen = string("assign_to_index__CPP(");
|
|
|
|
gen += GenExpr(lhs->GetOp1(), GEN_VAL_PTR) + ", " + "index_val__CPP({" + GenExpr(lhs->GetOp2(), GEN_VAL_PTR) +
|
|
"}), " + rhs_val_ptr + ")";
|
|
|
|
if ( ! top_level )
|
|
gen = GenericValPtrToGT(gen, rhs->GetType(), gt);
|
|
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenFieldAssign(const ExprPtr& lhs, const ExprPtr& rhs, const string& rhs_native,
|
|
const string& rhs_val_ptr, GenType gt, bool top_level) {
|
|
auto rec = lhs->GetOp1();
|
|
auto rec_gen = GenExpr(rec, GEN_VAL_PTR);
|
|
auto field = GenField(rec, lhs->AsFieldExpr()->Field());
|
|
|
|
if ( ! top_level ) {
|
|
auto gen = string("assign_field__CPP(") + rec_gen + ", " + field + ", " + rhs_val_ptr + ")";
|
|
return GenericValPtrToGT(gen, rhs->GetType(), gt);
|
|
}
|
|
|
|
auto rt = rhs ? rhs->GetType() : nullptr;
|
|
if ( rt && (IsNativeType(rt) || rt->Tag() == TYPE_STRING) )
|
|
return rec_gen + "->Assign(" + field + ", " + rhs_native + ")";
|
|
else
|
|
return rec_gen + "->Assign(" + field + ", " + rhs_val_ptr + ")";
|
|
}
|
|
|
|
string CPPCompile::GenListAssign(const ExprPtr& lhs, const ExprPtr& rhs) {
|
|
if ( rhs->Tag() != EXPR_NAME )
|
|
reporter->InternalError("compound RHS expression in multi-assignment");
|
|
|
|
string gen;
|
|
const auto& vars = lhs->AsListExpr()->Exprs();
|
|
|
|
auto n = vars.length();
|
|
for ( auto i = 0; i < n; ++i ) {
|
|
const auto& var_i = vars[i];
|
|
if ( var_i->Tag() != EXPR_NAME )
|
|
reporter->InternalError("compound LHS expression in multi-assignment");
|
|
const auto& t_i = var_i->GetType();
|
|
auto var = var_i->AsNameExpr();
|
|
|
|
auto rhs_i_base = GenExpr(rhs, GEN_DONT_CARE);
|
|
rhs_i_base += "->AsListVal()->Idx(" + Fmt(i) + ")";
|
|
|
|
auto rhs_i = GenericValPtrToGT(rhs_i_base, t_i, GEN_NATIVE);
|
|
|
|
gen += IDNameStr(var->Id()) + " = " + rhs_i;
|
|
|
|
if ( i < n - 1 )
|
|
gen += ", ";
|
|
}
|
|
|
|
return "(" + gen + ")";
|
|
}
|
|
|
|
string CPPCompile::GenVectorOp(const Expr* e, string op, const char* vec_op) {
|
|
auto t = e->GetType();
|
|
auto gen_t = GenTypeName(t);
|
|
auto gen = string("vec_op_") + vec_op + "__CPP(" + op + ", " + gen_t + ")";
|
|
|
|
if ( ! IsArithmetic(t->Yield()->Tag()) )
|
|
gen = string("vector_coerce_to__CPP(") + gen + ", " + gen_t + ")";
|
|
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenVectorOp(const Expr* e, string op1, string op2, const char* vec_op) {
|
|
auto& op1_t = e->GetOp1()->GetType();
|
|
auto& op2_t = e->GetOp2()->GetType();
|
|
|
|
if ( op1_t->Tag() != TYPE_VECTOR || op2_t->Tag() != TYPE_VECTOR ) {
|
|
// This is a deprecated mixed-scalar-and-vector operation.
|
|
// We don't support these. Arrange for linking errors.
|
|
reporter->Error("C++ generation does not support deprecated scalar-mixed-with-vector operations");
|
|
return "vec_scalar_mixed_with_vector()";
|
|
}
|
|
|
|
auto invoke = string(vec_op) + "__CPP(" + op1 + ", " + op2 + ")";
|
|
|
|
auto tag2 = op2_t->Yield()->Tag();
|
|
|
|
if ( tag2 == TYPE_STRING )
|
|
return string("str_vec_op_") + invoke;
|
|
if ( tag2 == TYPE_PATTERN )
|
|
return string("pat_vec_op_") + invoke;
|
|
|
|
auto gen = string("vec_op_") + invoke;
|
|
|
|
auto yt = e->GetType()->Yield()->Tag();
|
|
if ( ! IsArithmetic(yt) && yt != TYPE_STRING )
|
|
gen = string("vector_coerce_to__CPP(") + gen + ", " + GenTypeName(e->GetType()) + ")";
|
|
|
|
return gen;
|
|
}
|
|
|
|
string CPPCompile::GenLambdaClone(const LambdaExpr* l, bool all_deep) {
|
|
auto& ids = l->OuterIDs();
|
|
const auto& captures = l->GetType<FuncType>()->GetCaptures();
|
|
|
|
string cl_args;
|
|
|
|
for ( const auto& id : ids ) {
|
|
const auto& id_t = id->GetType();
|
|
auto arg = CaptureName(id);
|
|
|
|
if ( captures && ! IsNativeType(id_t) ) {
|
|
for ( const auto& c : *captures )
|
|
if ( id == c.Id() && (c.IsDeepCopy() || all_deep) )
|
|
arg = string("cast_intrusive<") + TypeName(id_t) + ">(" + arg + "->Clone())";
|
|
}
|
|
|
|
cl_args += ", " + arg;
|
|
}
|
|
|
|
return cl_args;
|
|
}
|
|
|
|
string CPPCompile::GenIntVector(const vector<int>& vec) {
|
|
string res("{ ");
|
|
|
|
for ( auto i = 0u; i < vec.size(); ++i ) {
|
|
res += Fmt(vec[i]);
|
|
|
|
if ( i < vec.size() - 1 )
|
|
res += ", ";
|
|
}
|
|
|
|
return res + " }";
|
|
}
|
|
|
|
string CPPCompile::GenField(const ExprPtr& rec, int field) {
|
|
auto t = TypeRep(rec->GetType());
|
|
auto rt = t->AsRecordType();
|
|
|
|
if ( field < rt->NumOrigFields() )
|
|
// Can use direct access.
|
|
return Fmt(field);
|
|
|
|
// Need to dynamically map the field.
|
|
int mapping_slot;
|
|
|
|
auto rfm = record_field_mappings.find(rt);
|
|
if ( rfm != record_field_mappings.end() && rfm->second.count(field) > 0 )
|
|
// We're already tracking this field.
|
|
mapping_slot = rfm->second[field];
|
|
|
|
else {
|
|
// New mapping.
|
|
mapping_slot = num_rf_mappings++;
|
|
|
|
auto pt = processed_types.find(rt);
|
|
ASSERT(pt != processed_types.end());
|
|
auto rt_offset = pt->second->Offset();
|
|
field_decls.emplace_back(rt_offset, rt->FieldDecl(field));
|
|
|
|
if ( rfm != record_field_mappings.end() )
|
|
// We're already tracking this record.
|
|
rfm->second[field] = mapping_slot;
|
|
else {
|
|
// Need to start tracking this record.
|
|
unordered_map<int, int> rt_mapping;
|
|
rt_mapping[field] = mapping_slot;
|
|
record_field_mappings[rt] = rt_mapping;
|
|
}
|
|
}
|
|
|
|
return string("field_mapping[") + Fmt(mapping_slot) + "]";
|
|
}
|
|
|
|
string CPPCompile::GenEnum(const TypePtr& t, const ValPtr& ev) {
|
|
auto et = TypeRep(t)->AsEnumType();
|
|
auto v = ev->AsEnum();
|
|
|
|
if ( ! et->HasRedefs() )
|
|
// Can use direct access.
|
|
return "zeek_int_t(" + std::to_string(v) + ")";
|
|
|
|
// Need to dynamically map the access.
|
|
int mapping_slot;
|
|
|
|
auto evm = enum_val_mappings.find(et);
|
|
if ( evm != enum_val_mappings.end() && evm->second.count(v) > 0 )
|
|
// We're already tracking this value.
|
|
mapping_slot = evm->second[v];
|
|
|
|
else {
|
|
// New mapping.
|
|
mapping_slot = num_ev_mappings++;
|
|
|
|
string enum_name = et->Lookup(v);
|
|
bool create_if_missing = standalone && obj_matches_opt_files(ev);
|
|
enum_names.emplace_back(EnumMappingInfo{TypeOffset(t), std::move(enum_name), create_if_missing});
|
|
|
|
if ( evm != enum_val_mappings.end() ) {
|
|
// We're already tracking this enum.
|
|
evm->second[v] = mapping_slot;
|
|
}
|
|
else {
|
|
// Need to start tracking this enum.
|
|
unordered_map<int, int> et_mapping;
|
|
et_mapping[v] = mapping_slot;
|
|
enum_val_mappings[et] = et_mapping;
|
|
}
|
|
}
|
|
|
|
return string("enum_mapping[") + Fmt(mapping_slot) + "]";
|
|
}
|
|
|
|
} // namespace zeek::detail
|