/* * Copyright (c) 2011 Jiri Svoboda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Stree (syntax tree) intermediate representation. */ #include #include #include #include "list.h" #include "mytypes.h" #include "stree.h" /** Allocate new module. * * @return New module */ stree_module_t *stree_module_new(void) { stree_module_t *module; module = calloc(1, sizeof(stree_module_t)); if (module == NULL) { printf("Memory allocation failed.\n"); exit(1); } list_init(&module->members); return module; } /** Allocate new module member. * * @param mc Module member class * @return New module member */ stree_modm_t *stree_modm_new(modm_class_t mc) { stree_modm_t *modm; modm = calloc(1, sizeof(stree_modm_t)); if (modm == NULL) { printf("Memory allocation failed.\n"); exit(1); } modm->mc = mc; return modm; } /** Allocate new CSI. * * @param cc CSI class * @return New CSI */ stree_csi_t *stree_csi_new(csi_class_t cc) { stree_csi_t *csi; csi = calloc(1, sizeof(stree_csi_t)); if (csi == NULL) { printf("Memory allocation failed.\n"); exit(1); } csi->cc = cc; csi->ancr_state = ws_unvisited; csi->name = NULL; csi->base_csi = NULL; list_init(&csi->inherit); list_init(&csi->impl_if_ti); list_init(&csi->members); return csi; } /** Allocate new CSI member. * * @param cc CSI member class * @return New CSI member */ stree_csimbr_t *stree_csimbr_new(csimbr_class_t cc) { stree_csimbr_t *csimbr; csimbr = calloc(1, sizeof(stree_csimbr_t)); if (csimbr == NULL) { printf("Memory allocation failed.\n"); exit(1); } csimbr->cc = cc; return csimbr; } /** Allocate new constructor. * * @return New constructor */ stree_ctor_t *stree_ctor_new(void) { stree_ctor_t *ctor; ctor = calloc(1, sizeof(stree_ctor_t)); if (ctor == NULL) { printf("Memory allocation failed.\n"); exit(1); } return ctor; } /** Allocate new member delegate. * * @return New member delegate */ stree_deleg_t *stree_deleg_new(void) { stree_deleg_t *deleg; deleg = calloc(1, sizeof(stree_deleg_t)); if (deleg == NULL) { printf("Memory allocation failed.\n"); exit(1); } return deleg; } /** Allocate new enum. * * @return New enum */ stree_enum_t *stree_enum_new(void) { stree_enum_t *enum_d; enum_d = calloc(1, sizeof(stree_enum_t)); if (enum_d == NULL) { printf("Memory allocation failed.\n"); exit(1); } return enum_d; } /** Allocate new enum member. * * @return New enum member */ stree_embr_t *stree_embr_new(void) { stree_embr_t *embr; embr = calloc(1, sizeof(stree_embr_t)); if (embr == NULL) { printf("Memory allocation failed.\n"); exit(1); } return embr; } /** Allocate new member function. * * @return New member function */ stree_fun_t *stree_fun_new(void) { stree_fun_t *fun; fun = calloc(1, sizeof(stree_fun_t)); if (fun == NULL) { printf("Memory allocation failed.\n"); exit(1); } return fun; } /** Allocate new member variable. * * @return New member variable */ stree_var_t *stree_var_new(void) { stree_var_t *var; var = calloc(1, sizeof(stree_var_t)); if (var == NULL) { printf("Memory allocation failed.\n"); exit(1); } return var; } /** Allocate new property. * * @return New property */ stree_prop_t *stree_prop_new(void) { stree_prop_t *prop; prop = calloc(1, sizeof(stree_prop_t)); if (prop == NULL) { printf("Memory allocation failed.\n"); exit(1); } return prop; } /** Allocate new type argument. * * @return New type argument */ stree_targ_t *stree_targ_new(void) { stree_targ_t *targ; targ = calloc(1, sizeof(stree_targ_t)); if (targ == NULL) { printf("Memory allocation failed.\n"); exit(1); } return targ; } /** Allocate new symbol attribute. * * @param sac Symbol attribute class * @return New symbol attribute */ stree_symbol_attr_t *stree_symbol_attr_new(symbol_attr_class_t sac) { stree_symbol_attr_t *symbol_attr; symbol_attr = calloc(1, sizeof(stree_symbol_attr_t)); if (symbol_attr == NULL) { printf("Memory allocation failed.\n"); exit(1); } symbol_attr->sac = sac; return symbol_attr; } /** Allocate new procedure. * * @return New procedure */ stree_proc_t *stree_proc_new(void) { stree_proc_t *proc; proc = calloc(1, sizeof(stree_proc_t)); if (proc == NULL) { printf("Memory allocation failed.\n"); exit(1); } return proc; } /** Allocate new procedure argument. * * @return New procedure argument */ stree_proc_arg_t *stree_proc_arg_new(void) { stree_proc_arg_t *proc_arg; proc_arg = calloc(1, sizeof(stree_proc_arg_t)); if (proc_arg == NULL) { printf("Memory allocation failed.\n"); exit(1); } return proc_arg; } /** Allocate new function signature. * * @return New procedure argument */ stree_fun_sig_t *stree_fun_sig_new(void) { stree_fun_sig_t *fun_sig; fun_sig = calloc(1, sizeof(stree_fun_sig_t)); if (fun_sig == NULL) { printf("Memory allocation failed.\n"); exit(1); } return fun_sig; } /** Allocate new procedure argument attribute. * * @param Argument attribute class * @return New procedure argument attribute */ stree_arg_attr_t *stree_arg_attr_new(arg_attr_class_t aac) { stree_arg_attr_t *arg_attr; arg_attr = calloc(1, sizeof(stree_arg_attr_t)); if (arg_attr == NULL) { printf("Memory allocation failed.\n"); exit(1); } arg_attr->aac = aac; return arg_attr; } /** Allocate new statement. * * @param sc Statement class * @return New statement */ stree_stat_t *stree_stat_new(stat_class_t sc) { stree_stat_t *stat; stat = calloc(1, sizeof(stree_stat_t)); if (stat == NULL) { printf("Memory allocation failed.\n"); exit(1); } stat->sc = sc; return stat; } /** Allocate new local variable declaration. * * @return New local variable declaration */ stree_vdecl_t *stree_vdecl_new(void) { stree_vdecl_t *vdecl_s; vdecl_s = calloc(1, sizeof(stree_vdecl_t)); if (vdecl_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return vdecl_s; } /** Allocate new @c if statement. * * @return New @c if statement */ stree_if_t *stree_if_new(void) { stree_if_t *if_s; if_s = calloc(1, sizeof(stree_if_t)); if (if_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return if_s; } /** Allocate new @c switch statement. * * @return New @c if statement */ stree_switch_t *stree_switch_new(void) { stree_switch_t *switch_s; switch_s = calloc(1, sizeof(stree_switch_t)); if (switch_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return switch_s; } /** Allocate new @c while statement. * * @return New @c while statement */ stree_while_t *stree_while_new(void) { stree_while_t *while_s; while_s = calloc(1, sizeof(stree_while_t)); if (while_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return while_s; } /** Allocate new @c for statement. * * @return New @c for statement */ stree_for_t *stree_for_new(void) { stree_for_t *for_s; for_s = calloc(1, sizeof(stree_for_t)); if (for_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return for_s; } /** Allocate new @c raise statement. * * @return New @c raise statement */ stree_raise_t *stree_raise_new(void) { stree_raise_t *raise_s; raise_s = calloc(1, sizeof(stree_raise_t)); if (raise_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return raise_s; } /** Allocate new @c break statement. * * @return New @c break statement */ stree_break_t *stree_break_new(void) { stree_break_t *break_s; break_s = calloc(1, sizeof(stree_break_t)); if (break_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return break_s; } /** Allocate new @c return statement. * * @return New @c return statement */ stree_return_t *stree_return_new(void) { stree_return_t *return_s; return_s = calloc(1, sizeof(stree_return_t)); if (return_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return return_s; } /** Allocate new with-except-finally statement. * * @return New with-except-finally statement. */ stree_wef_t *stree_wef_new(void) { stree_wef_t *wef_s; wef_s = calloc(1, sizeof(stree_wef_t)); if (wef_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return wef_s; } /** Allocate new expression statement. * * @return New expression statement */ stree_exps_t *stree_exps_new(void) { stree_exps_t *exp_s; exp_s = calloc(1, sizeof(stree_exps_t)); if (exp_s == NULL) { printf("Memory allocation failed.\n"); exit(1); } return exp_s; } /** Allocate new @c except clause. * * @return New @c except clause */ stree_except_t *stree_except_new(void) { stree_except_t *except_c; except_c = calloc(1, sizeof(stree_except_t)); if (except_c == NULL) { printf("Memory allocation failed.\n"); exit(1); } return except_c; } /** Allocate new @c if/elif clause. * * @return New @c if/elif clause */ stree_if_clause_t *stree_if_clause_new(void) { stree_if_clause_t *if_clause; if_clause = calloc(1, sizeof(stree_if_clause_t)); if (if_clause == NULL) { printf("Memory allocation failed.\n"); exit(1); } return if_clause; } /** Allocate new @c when clause. * * @return New @c when clause */ stree_when_t *stree_when_new(void) { stree_when_t *when_c; when_c = calloc(1, sizeof(stree_when_t)); if (when_c == NULL) { printf("Memory allocation failed.\n"); exit(1); } return when_c; } /** Allocate new statement block. * * @return New statement block */ stree_block_t *stree_block_new(void) { stree_block_t *block; block = calloc(1, sizeof(stree_block_t)); if (block == NULL) { printf("Memory allocation failed.\n"); exit(1); } return block; } /** Allocate new expression. * * @param ec Expression class * @return New expression */ stree_expr_t *stree_expr_new(expr_class_t ec) { stree_expr_t *expr; expr = calloc(1, sizeof(stree_expr_t)); if (expr == NULL) { printf("Memory allocation failed.\n"); exit(1); } expr->ec = ec; return expr; } /** Allocate new assignment. * * @param ac Assignment class * @return New assignment */ stree_assign_t *stree_assign_new(assign_class_t ac) { stree_assign_t *assign; assign = calloc(1, sizeof(stree_assign_t)); if (assign == NULL) { printf("Memory allocation failed.\n"); exit(1); } assign->ac = ac; return assign; } /** Allocate new binary operation. * * @return New binary operation */ stree_binop_t *stree_binop_new(binop_class_t bc) { stree_binop_t *binop; binop = calloc(1, sizeof(stree_binop_t)); if (binop == NULL) { printf("Memory allocation failed.\n"); exit(1); } binop->bc = bc; return binop; } /** Allocate new unary operation. * * @param uc Unary operation class * @return New unary operation */ stree_unop_t *stree_unop_new(unop_class_t uc) { stree_unop_t *unop; unop = calloc(1, sizeof(stree_unop_t)); if (unop == NULL) { printf("Memory allocation failed.\n"); exit(1); } unop->uc = uc; return unop; } /** Allocate new @c new operation. * * @return New @c new operation */ stree_new_t *stree_new_new(void) { stree_new_t *new_op; new_op = calloc(1, sizeof(stree_new_t)); if (new_op == NULL) { printf("Memory allocation failed.\n"); exit(1); } return new_op; } /** Allocate new . * * @return New */ stree_access_t *stree_access_new(void) { stree_access_t *access; access = calloc(1, sizeof(stree_access_t)); if (access == NULL) { printf("Memory allocation failed.\n"); exit(1); } return access; } /** Allocate new function call operation. * * @return New function call operation */ stree_call_t *stree_call_new(void) { stree_call_t *call; call = calloc(1, sizeof(stree_call_t)); if (call == NULL) { printf("Memory allocation failed.\n"); exit(1); } return call; } /** Allocate new indexing operation. * * @return New indexing operation */ stree_index_t *stree_index_new(void) { stree_index_t *index; index = calloc(1, sizeof(stree_index_t)); if (index == NULL) { printf("Memory allocation failed.\n"); exit(1); } return index; } /** Allocate new as conversion. * * @return New as conversion */ stree_as_t *stree_as_new(void) { stree_as_t *as_expr; as_expr = calloc(1, sizeof(stree_as_t)); if (as_expr == NULL) { printf("Memory allocation failed.\n"); exit(1); } return as_expr; } /** Allocate new boxing operation. * * @return New boxing operation */ stree_box_t *stree_box_new(void) { stree_box_t *box_expr; box_expr = calloc(1, sizeof(stree_box_t)); if (box_expr == NULL) { printf("Memory allocation failed.\n"); exit(1); } return box_expr; } /** Allocate new name reference operation. * * @return New name reference operation */ stree_nameref_t *stree_nameref_new(void) { stree_nameref_t *nameref; nameref = calloc(1, sizeof(stree_nameref_t)); if (nameref == NULL) { printf("Memory allocation failed.\n"); exit(1); } return nameref; } /** Allocate new identifier. * * @return New identifier */ stree_ident_t *stree_ident_new(void) { stree_ident_t *ident; ident = calloc(1, sizeof(stree_ident_t)); if (ident == NULL) { printf("Memory allocation failed.\n"); exit(1); } return ident; } /** Allocate new literal. * * @param ltc Literal class * @return New literal */ stree_literal_t *stree_literal_new(literal_class_t ltc) { stree_literal_t *literal; literal = calloc(1, sizeof(stree_literal_t)); if (literal == NULL) { printf("Memory allocation failed.\n"); exit(1); } literal->ltc = ltc; return literal; } /** Allocate new @c self reference. * * @return New @c self reference */ stree_self_ref_t *stree_self_ref_new(void) { stree_self_ref_t *self_ref; self_ref = calloc(1, sizeof(stree_self_ref_t)); if (self_ref == NULL) { printf("Memory allocation failed.\n"); exit(1); } return self_ref; } /** Allocate new type expression * * @return New type expression */ stree_texpr_t *stree_texpr_new(texpr_class_t tc) { stree_texpr_t *texpr; texpr = calloc(1, sizeof(stree_texpr_t)); if (texpr == NULL) { printf("Memory allocation failed.\n"); exit(1); } texpr->tc = tc; return texpr; } /** Allocate new type access operation. * * @return New type access operation */ stree_taccess_t *stree_taccess_new(void) { stree_taccess_t *taccess; taccess = calloc(1, sizeof(stree_taccess_t)); if (taccess == NULL) { printf("Memory allocation failed.\n"); exit(1); } return taccess; } /** Allocate new type application operation. * * @return New type application operation */ stree_tapply_t *stree_tapply_new(void) { stree_tapply_t *tapply; tapply = calloc(1, sizeof(stree_tapply_t)); if (tapply == NULL) { printf("Memory allocation failed.\n"); exit(1); } return tapply; } /** Allocate new type indexing operation. * * @return New type indexing operation */ stree_tindex_t *stree_tindex_new(void) { stree_tindex_t *tindex; tindex = calloc(1, sizeof(stree_tindex_t)); if (tindex == NULL) { printf("Memory allocation failed.\n"); exit(1); } return tindex; } /** Allocate new type literal. * * @return New type literal */ stree_tliteral_t *stree_tliteral_new(tliteral_class_t tlc) { stree_tliteral_t *tliteral; tliteral = calloc(1, sizeof(stree_tliteral_t)); if (tliteral == NULL) { printf("Memory allocation failed.\n"); exit(1); } tliteral->tlc = tlc; return tliteral; } /** Allocate new type name reference. * * @return New type name reference */ stree_tnameref_t *stree_tnameref_new(void) { stree_tnameref_t *tnameref; tnameref = calloc(1, sizeof(stree_tnameref_t)); if (tnameref == NULL) { printf("Memory allocation failed.\n"); exit(1); } return tnameref; } /** Allocate new symbol. * * @return New symbol */ stree_symbol_t *stree_symbol_new(symbol_class_t sc) { stree_symbol_t *symbol; symbol = calloc(1, sizeof(stree_symbol_t)); if (symbol == NULL) { printf("Memory allocation failed.\n"); exit(1); } symbol->sc = sc; list_init(&symbol->attr); return symbol; } /** Allocate new program. * * @return New program */ stree_program_t *stree_program_new(void) { stree_program_t *program; program = calloc(1, sizeof(stree_program_t)); if (program == NULL) { printf("Memory allocation failed.\n"); exit(1); } return program; } /** Determine if @a symbol has attribute of class @a sac. * * @param symbol Symbol * @param sac Symbol attribute class * @return @c b_true if yes, @c b_false if no */ bool_t stree_symbol_has_attr(stree_symbol_t *symbol, symbol_attr_class_t sac) { list_node_t *node; stree_symbol_attr_t *attr; node = list_first(&symbol->attr); while (node != NULL) { attr = list_node_data(node, stree_symbol_attr_t *); if (attr->sac == sac) return b_true; node = list_next(&symbol->attr, node); } return b_false; } /** Determine if argument @a arg has attribute of class @a aac. * * @param arg Formal procedure argument * @param aac Argument attribute class * @return @c b_true if yes, @c b_false if no. */ bool_t stree_arg_has_attr(stree_proc_arg_t *arg, arg_attr_class_t aac) { list_node_t *node; stree_arg_attr_t *attr; node = list_first(&arg->attr); while (node != NULL) { attr = list_node_data(node, stree_arg_attr_t *); if (attr->aac == aac) return b_true; node = list_next(&arg->attr, node); } return b_false; } /** Determine wheter @a a is derived (transitively) from @a b. * * XXX This does not work right with generics. * * @param a Derived CSI. * @param b Base CSI. * @return @c b_true if @a a is equal to or directly or indirectly * derived from @a b. */ bool_t stree_is_csi_derived_from_csi(stree_csi_t *a, stree_csi_t *b) { stree_csi_t *csi; csi = a; while (csi != NULL) { if (csi == b) return b_true; csi = csi->base_csi; } /* We went all the way to the root and did not find b. */ return b_false; } /** Determine if @a symbol is static. * * @param symbol Symbol * @return @c b_true if symbol is static, @c b_false otherwise */ bool_t stree_symbol_is_static(stree_symbol_t *symbol) { /* Module-wide symbols are static. */ if (symbol->outer_csi == NULL) return b_true; /* Symbols with @c static attribute are static. */ if (stree_symbol_has_attr(symbol, sac_static)) return b_true; switch (symbol->sc) { case sc_csi: case sc_deleg: case sc_enum: return b_true; case sc_ctor: case sc_fun: case sc_var: case sc_prop: break; } return b_false; } /** Search for CSI type argument of the given name. * * @param csi CSI to look in * @param ident Identifier of the type argument * @return Type argument declaration or @c NULL if not found */ stree_targ_t *stree_csi_find_targ(stree_csi_t *csi, stree_ident_t *ident) { list_node_t *targ_n; stree_targ_t *targ; targ_n = list_first(&csi->targ); while (targ_n != NULL) { targ = list_node_data(targ_n, stree_targ_t *); if (targ->name->sid == ident->sid) return targ; targ_n = list_next(&csi->targ, targ_n); } /* No match */ return NULL; } /** Search for enum member of the given name. * * @param enum_d Enum to look in * @param ident Identifier of the enum member * @return Enum member declaration or @c NULL if not found */ stree_embr_t *stree_enum_find_mbr(stree_enum_t *enum_d, stree_ident_t *ident) { list_node_t *embr_n; stree_embr_t *embr; embr_n = list_first(&enum_d->members); while (embr_n != NULL) { embr = list_node_data(embr_n, stree_embr_t *); if (embr->name->sid == ident->sid) return embr; embr_n = list_next(&enum_d->members, embr_n); } /* No match */ return NULL; } /** Get CSI member name. * * @param csimbr CSI member * @return Member name */ stree_ident_t *stree_csimbr_get_name(stree_csimbr_t *csimbr) { stree_ident_t *mbr_name; /* Keep compiler happy. */ mbr_name = NULL; switch (csimbr->cc) { case csimbr_csi: mbr_name = csimbr->u.csi->name; break; case csimbr_ctor: mbr_name = csimbr->u.ctor->name; break; case csimbr_deleg: mbr_name = csimbr->u.deleg->name; break; case csimbr_enum: mbr_name = csimbr->u.enum_d->name; break; case csimbr_fun: mbr_name = csimbr->u.fun->name; break; case csimbr_var: mbr_name = csimbr->u.var->name; break; case csimbr_prop: mbr_name = csimbr->u.prop->name; break; } return mbr_name; }