+
+static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
+ va_end(ap);
+}
+
+/* exposed */
+intrin_t *intrin_init(parser_t *parser) {
+ intrin_t *intrin = (intrin_t*)mem_a(sizeof(intrin_t));
+ intrin->parser = parser;
+ intrin->fold = parser->fold;
+ intrin->intrinsics = NULL;
+
+ vec_append(intrin->intrinsics, sizeof(intrinsics)/sizeof(*intrinsics), intrinsics);
+
+ return intrin;
+}
+
+void intrin_cleanup(intrin_t *intrin) {
+ vec_free(intrin->intrinsics);
+ mem_d(intrin);
+}
+
+ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
+ size_t i;
+
+ if (!value || !value->name)
+ return NULL;
+
+ for (i = 0; i < vec_size(intrin->intrinsics); i++) {
+ if (!strcmp(value->name, intrin->intrinsics[i].name)) {
+ if (intrin->intrinsics[i].args != vec_size(exprs))
+ return NULL;
+ /* +10 to skip the "__builtin_" substring in the string */
+ return fold_intrin(intrin->fold, value->name + 10, exprs);
+ }
+ }
+
+ return NULL;
+}
+
+ast_expression *intrin_func(intrin_t *intrin, const char *name) {
+ size_t i = 0;
+ void *find;
+
+ /* try current first */
+ if ((find = (void*)parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
+ for (i = 0; i < vec_size(intrin->parser->functions); ++i)
+ if (((ast_value*)find)->name && !strcmp(intrin->parser->functions[i]->name, ((ast_value*)find)->name) && intrin->parser->functions[i]->builtin < 0)
+ return (ast_expression*)find;
+ /* try name second */
+ for (i = 0; i < vec_size(intrin->intrinsics); i++)
+ if (!strcmp(intrin->intrinsics[i].name, name))
+ return intrin->intrinsics[i].intrin(intrin);
+ /* try alias third */
+ for (i = 0; i < vec_size(intrin->intrinsics); i++)
+ if (!strcmp(intrin->intrinsics[i].alias, name))
+ return intrin->intrinsics[i].intrin(intrin);
+
+ intrin_error(intrin, "need function: `%s` compiler depends on it", name);
+ return NULL;
+}