def desugar_equation(self, params, param_types, result_type, equation): position = equation.position patterns = equation.lhs.application_args() body = equation.rhs if len(patterns) != len(params): self.fail('equations-arity-mismatch', name=name, position=position) self._env.open_scope() # Equation scope fvs = set() for var in syntax.free_variables_list(patterns): if not self._env.is_defined(var): fvs.add(var) self._env.define(var, syntax.Metavar(prefix="t", position=position)) # TODO: allow forced binding by prefixing a variable with "." if len(equation.where) == 0: d_type, d_body = self.check_expr(body) else: d_type, d_body = self.check_let( syntax.Let(declarations=equation.where, body=body, position=position)) self.unify_types(d_type, result_type) unif_goals = [] for param, pattern, t_param in zip(params, patterns, param_types): t_pattern, e_pattern = self.check_expr(pattern) self.unify_types(t_param, t_pattern) unif_goals.append(syntax.unify(param, e_pattern)) alternative = syntax.fresh_many( fvs, syntax.sequence_many1(unif_goals, d_body)) self._env.close_scope() # Equation scope return alternative
def parse_program(self): position = self.current_position() self.match(token.BEGIN) data_declarations = [] value_declarations = [] while self._token.type() == token.DELIM: self.match(token.DELIM) for decl in self.parse_toplevel_declaration(): if decl.is_data_declaration(): data_declarations.append(decl) else: value_declarations.append(decl) self.match(token.END) self.match(token.EOF) return syntax.Program( data_declarations=data_declarations, body=syntax.Let(declarations=value_declarations, body=syntax.Variable(name="main", position=position), position=position), position=position, )
def check_let(self, expr): # Check kinds and extend environment # to allow for recursive definitions. definitions, definition_keys, type_declarations = \ self.check_let_declarations_well_formed(expr) # TODO: Dependency graph graph = self.dependency_graph(definitions) partition = dependencies.partition_dependencies(graph) desugared_declarations = [] for part in partition: part_definitions = {} part_type_declarations = {} for x in part: part_definitions[x] = definitions[x] if x in type_declarations: part_type_declarations[x] = type_declarations[x] part_definition_keys = [] for k in definition_keys: if k in part_definitions: part_definition_keys.append(k) self._env.open_scope() for name, defs in part_definitions.items(): self._env.define(name, syntax.Metavar(prefix='t', position=defs[0].position)) e_decls = [] for name in part_definition_keys: e_decls.append( self.desugar_definition(name, part_definitions[name]) ) self.generalize_types_in_current_scope() self.check_declared_instantiate_real(part_type_declarations) # To reconstruct the final AST ds = [] for e_decl in e_decls: t_decl = syntax.TypeDeclaration( name=e_decl.lhs.name, type=self._env.value(e_decl.lhs.name), position=e_decl.position ) ds.append(t_decl) ds.append(e_decl) desugared_declarations.append(ds) t_body, e_body = self.check_expr(expr.body) for part in reversed(partition): self._env.close_scope() e_body = syntax.Let( declarations=desugared_declarations.pop(), body=e_body, position=expr.position) return t_body, e_body
def p_expr_let(p: Any) -> None: 'expr : LET sortedvar EQUAL expr IN expr' p[0] = syntax.Let(p.slice[1], p[2], p[4], p[6])
def p_expr_let(p: Any) -> None: 'expr : LET sortedvar EQUAL expr IN expr' sv: syntax.SortedVar = p[2] val: syntax.Expr = p[4] body: syntax.Expr = p[6] p[0] = syntax.Let(sv, val, body, span=loc_join(p.slice[1], body.span))
def relaxation_action_def(prog: syntax.Program, actives: Optional[Dict[syntax.SortDecl, syntax.RelationDecl]] = None, fresh: bool = True) -> syntax.DefinitionDecl: decrease_name = (prog.scope.fresh('decrease_domain') if fresh else 'decrease_domain') mods: Tuple[syntax.ModifiesClause, ...] = () conjs: List[Expr] = [] if actives is None: actives = active_rel_by_sort(prog) # a conjunct allowing each domain to decrease new_mods, new_conjs = relax_actives_action_chunk(prog.scope, actives) mods += new_mods conjs += new_conjs # constants are active for const in prog.constants(): conjs.append( syntax.New( syntax.Apply( actives[syntax.get_decl_from_sort(const.sort)].name, (syntax.Id(const.name), )))) # functions map active to active for func in prog.functions(): names: List[str] = [] func_conjs = [] for arg_sort in func.arity: arg_sort_decl = syntax.get_decl_from_sort(arg_sort) name = prog.scope.fresh(arg_sort_decl.name[0].upper(), also_avoid=names) names.append(name) func_conjs.append( syntax.New( syntax.Apply(actives[arg_sort_decl].name, (syntax.Id(name), )))) ap_func = syntax.Apply(func.name, tuple(syntax.Id(name) for name in names)) name = prog.scope.fresh('y', also_avoid=names) active_func = syntax.Let( syntax.SortedVar(name, func.sort), ap_func, syntax.New( syntax.Apply( actives[syntax.get_decl_from_sort(func.sort)].name, (syntax.Id(name), )))) conjs.append( syntax.Forall( tuple(syntax.SortedVar(name, None) for name in names), syntax.Implies(syntax.And(*func_conjs), active_func))) # (relativized) axioms hold after relaxation for axiom in prog.axioms(): if not syntax.is_universal(axiom.expr): conjs.append(syntax.relativize_quantifiers(actives, axiom.expr)) # derived relations have the same interpretation on the active domain for rel in prog.derived_relations(): names = [] rel_conjs = [] for arg_sort in rel.arity: arg_sort_decl = syntax.get_decl_from_sort(arg_sort) name = prog.scope.fresh(arg_sort_decl.name[0].upper(), also_avoid=names) names.append(name) rel_conjs.append( syntax.Apply(actives[arg_sort_decl].name, (syntax.Id(name), ))) ap_rel = syntax.Apply(rel.name, tuple(syntax.Id(name) for name in names)) conjs.append( syntax.Forall( tuple(syntax.SortedVar(name, None) for name in names), syntax.Implies(syntax.And(*rel_conjs), syntax.Iff(syntax.New(ap_rel), ap_rel)))) return syntax.DefinitionDecl(is_public_transition=True, num_states=2, name=decrease_name, params=(), mods=mods, expr=syntax.And(*conjs))
def check_let(self, expr): # Check kinds and extend environment # to allow for recursive definitions. declared_names = set() definitions = {} definition_keys = [] self._env.open_scope() type_declarations = [] for decl in expr.declarations: if decl.is_type_declaration(): decl = self.check_type_declaration(decl) declared_names.add(decl.name) type_declarations.append(decl) elif decl.is_definition(): head = decl.lhs.application_head() if not head.is_variable(): self.fail('declaration-head-is-not-variable', head=head, position=decl.position) declared_names.add(head.name) if head.name not in definitions: definition_keys.append(head.name) definitions[head.name] = [] definitions[head.name].append(decl) if not self._env.is_locally_defined(head.name): self._env.define( head.name, syntax.Metavar(prefix='t', position=decl.position)) else: raise Exception('Check for declaration not implemented.') defined_names = set(definitions.keys()) if declared_names != defined_names: missing = declared_names - defined_names self.fail('name-declared-but-not-defined', name=missing.pop(), position=expr.position) e_decls = [] for name in definition_keys: e_decls.append(self.desugar_definition(name, definitions[name])) self.generalize_types_in_current_scope() self.check_declared_instantiate_real(type_declarations) body_type, desugared_body = self.check_expr(expr.body) # To reconstruct the final AST desugared_declarations = [] for e_decl in e_decls: t_decl = syntax.TypeDeclaration(name=e_decl.lhs.name, type=self._env.value( e_decl.lhs.name), position=e_decl.position) desugared_declarations.append(t_decl) desugared_declarations.append(e_decl) self._env.close_scope() return (body_type, syntax.Let(declarations=desugared_declarations, body=desugared_body, position=expr.position))