Ejemplo n.º 1
0
// Document the packages in the given program
static void doc_packages(docgen_t* docgen, ast_t* ast)
{
  assert(ast != NULL);
  assert(ast_id(ast) == TK_PROGRAM);

  // The Main package appears first, other packages in alphabetical order
  ast_t* package_1 = NULL;

  ast_list_t packages = { NULL, NULL, NULL };

  // Sort packages
  for(ast_t* p = ast_child(ast); p != NULL; p = ast_sibling(p))
  {
    assert(ast_id(p) == TK_PACKAGE);

    if(strcmp(package_name(p), "$0") == 0)
    {
      assert(package_1 == NULL);
      package_1 = p;
    }
    else
    {
      const char* name = package_qualified_name(p);
      doc_list_add(&packages, p, name);
    }
  }

  // Process packages
  assert(package_1 != NULL);
  doc_package(docgen, package_1);

  for(ast_list_t* p = packages.next; p != NULL; p = p->next)
    doc_package(docgen, p->ast);
}
Ejemplo n.º 2
0
// Process the given provided method for the given entity.
// The method passed should be reified already and will be freed by this
// function.
static bool provided_method(ast_t* entity, ast_t* reified_method,
  ast_t* raw_method, ast_t** last_method)
{
  assert(entity != NULL);
  assert(reified_method != NULL);
  assert(last_method != NULL);

  const char* entity_name = ast_name(ast_child(entity));

  if(ast_id(reified_method) == TK_BE || ast_id(reified_method) == TK_NEW)
  {
    // Modify return type to the inheritting type
    ast_t* ret_type = ast_childidx(reified_method, 4);
    assert(ast_id(ret_type) == TK_NOMINAL);

    const char* pkg_name = package_name(ast_nearest(entity, TK_PACKAGE));
    ast_set_name(ast_childidx(ret_type, 0), pkg_name);
    ast_set_name(ast_childidx(ret_type, 1), entity_name);
  }

  // Ignore docstring
  ast_t* doc = ast_childidx(reified_method, 7);

  if(ast_id(doc) == TK_STRING)
  {
    ast_set_name(doc, "");
    ast_setid(doc, TK_NONE);
  }

  // Check for existing method of the same name
  const char* name = ast_name(ast_childidx(reified_method, 1));
  assert(name != NULL);

  ast_t* existing = ast_get(entity, name, NULL);

  if(existing != NULL && is_field(existing))
  {
    ast_error(existing, "field '%s' clashes with provided method", name);
    ast_error(raw_method, "method is defined here");
    ast_free_unattached(reified_method);
    return false;
  }

  existing = add_method(entity, existing, reified_method, last_method);

  if(existing == NULL)
  {
    ast_free_unattached(reified_method);
    return false;
  }

  method_t* info = (method_t*)ast_data(existing);
  assert(info != NULL);

  if(!record_default_body(reified_method, raw_method, info))
    ast_free_unattached(reified_method);

  return true;
}
Ejemplo n.º 3
0
static ast_result_t sugar_module(ast_t* ast)
{
  ast_t* docstring = ast_child(ast);

  ast_t* package = ast_parent(ast);
  assert(ast_id(package) == TK_PACKAGE);

  if(strcmp(package_name(package), "$0") != 0)
  {
    // Every module not in builtin has an implicit use builtin command.
    // Since builtin is always the first package processed it is $0.
    BUILD(builtin, ast,
      NODE(TK_USE,
      NONE
      STRING(stringtab("builtin"))
      NONE));

    ast_add(ast, builtin);
  }

  if((docstring == NULL) || (ast_id(docstring) != TK_STRING))
    return AST_OK;

  ast_t* package_docstring = ast_childlast(package);

  if(ast_id(package_docstring) == TK_STRING)
  {
    ast_error(docstring, "the package already has a docstring");
    ast_error(package_docstring, "the existing docstring is here");
    return AST_ERROR;
  }

  ast_append(package, docstring);
  ast_remove(docstring);
  return AST_OK;
}
Ejemplo n.º 4
0
ast_t* package_id(ast_t* ast)
{
  return ast_from_string(ast, package_name(ast));
}
Ejemplo n.º 5
0
int main(int argc, char** argv) {
    const double PI(3.141592653589793);

    if (argc != 4) {
        std::cout << "usage:" << std::endl;
        std::cout << "package_scene path_scene output" << std::endl;
        return 0;
    }
    ros::init(argc, argv, "dart_test");

    ros::NodeHandle nh_;

    std::string package_name( argv[1] );
    std::string scene_urdf( argv[2] );

    ros::Rate loop_rate(400);

    ros::Publisher joint_state_pub_;
    joint_state_pub_ = nh_.advertise<sensor_msgs::JointState>("/joint_states", 10);
    tf::TransformBroadcaster br;
    MarkerPublisher markers_pub(nh_);

    std::string package_path_barrett = ros::package::getPath("barrett_hand_defs");
    std::string package_path = ros::package::getPath(package_name);

    // Load the Skeleton from a file
    dart::utils::DartLoader loader;
    loader.addPackageDirectory("barrett_hand_defs", package_path_barrett);
    loader.addPackageDirectory("barrett_hand_sim_dart", package_path);

    boost::shared_ptr<GraspSpecification > gspec = GraspSpecification::readFromUrdf(package_path + scene_urdf);

    dart::dynamics::SkeletonPtr scene( loader.parseSkeleton(package_path + scene_urdf) );
    scene->enableSelfCollision(true);

    dart::dynamics::SkeletonPtr bh( loader.parseSkeleton(package_path_barrett + "/robots/barrett_hand.urdf") );
    Eigen::Isometry3d tf;
    tf = scene->getBodyNode("gripper_mount_link")->getRelativeTransform();
    bh->getJoint(0)->setTransformFromParentBodyNode(tf);

    dart::simulation::World* world = new dart::simulation::World();

    world->addSkeleton(scene);
    world->addSkeleton(bh);

    Eigen::Vector3d grav(0,0,-1);
    world->setGravity(grav);

    GripperController gc;

    double Kc = 400.0;
    double KcDivTi = Kc / 1.0;
    gc.addJoint("right_HandFingerOneKnuckleOneJoint", Kc, KcDivTi, 0.0, 0.001, 50.0, true, false);
    gc.addJoint("right_HandFingerOneKnuckleTwoJoint", Kc, KcDivTi, 0.0, 0.001, 50.0, false, true);
    gc.addJoint("right_HandFingerTwoKnuckleTwoJoint", Kc, KcDivTi, 0.0, 0.001, 50.0, false, true);
    gc.addJoint("right_HandFingerThreeKnuckleTwoJoint", Kc, KcDivTi, 0.0, 0.001, 50.0, false, true);

    gc.addJointMimic("right_HandFingerTwoKnuckleOneJoint", 2.0*Kc, KcDivTi, 0.0, 0.001, 50.0, true, "right_HandFingerOneKnuckleOneJoint", 1.0, 0.0);
    gc.addJointMimic("right_HandFingerOneKnuckleThreeJoint", 2.0*Kc, KcDivTi, 0.0, 0.001, 50.0, false, "right_HandFingerOneKnuckleTwoJoint", 0.333333, 0.0);
    gc.addJointMimic("right_HandFingerTwoKnuckleThreeJoint", 2.0*Kc, KcDivTi, 0.0, 0.001, 50.0, false, "right_HandFingerTwoKnuckleTwoJoint", 0.333333, 0.0);
    gc.addJointMimic("right_HandFingerThreeKnuckleThreeJoint", 2.0*Kc, KcDivTi, 0.0, 0.001, 50.0, false, "right_HandFingerThreeKnuckleTwoJoint", 0.333333, 0.0);

    gc.setGoalPosition("right_HandFingerOneKnuckleOneJoint", gspec->getGoalPosition("right_HandFingerOneKnuckleOneJoint"));
    gc.setGoalPosition("right_HandFingerOneKnuckleTwoJoint", gspec->getGoalPosition("right_HandFingerOneKnuckleTwoJoint"));
    gc.setGoalPosition("right_HandFingerTwoKnuckleTwoJoint", gspec->getGoalPosition("right_HandFingerTwoKnuckleTwoJoint"));
    gc.setGoalPosition("right_HandFingerThreeKnuckleTwoJoint", gspec->getGoalPosition("right_HandFingerThreeKnuckleTwoJoint"));

    std::map<std::string, double> joint_q_map;
    joint_q_map["right_HandFingerOneKnuckleOneJoint"] = gspec->getInitPosition("right_HandFingerOneKnuckleOneJoint");
    joint_q_map["right_HandFingerTwoKnuckleOneJoint"] = gspec->getInitPosition("right_HandFingerOneKnuckleOneJoint");
    joint_q_map["right_HandFingerOneKnuckleTwoJoint"] = gspec->getInitPosition("right_HandFingerOneKnuckleTwoJoint");
    joint_q_map["right_HandFingerOneKnuckleThreeJoint"] = 0.333333 * gspec->getInitPosition("right_HandFingerOneKnuckleTwoJoint");
    joint_q_map["right_HandFingerTwoKnuckleTwoJoint"] = gspec->getInitPosition("right_HandFingerTwoKnuckleTwoJoint");
    joint_q_map["right_HandFingerTwoKnuckleThreeJoint"] = 0.333333 * gspec->getInitPosition("right_HandFingerTwoKnuckleTwoJoint");
    joint_q_map["right_HandFingerThreeKnuckleTwoJoint"] = gspec->getInitPosition("right_HandFingerThreeKnuckleTwoJoint");
    joint_q_map["right_HandFingerThreeKnuckleThreeJoint"] = 0.333333 * gspec->getInitPosition("right_HandFingerThreeKnuckleTwoJoint");

    for (std::vector<std::string >::const_iterator it = gc.getJointNames().begin(); it != gc.getJointNames().end(); it++) {
        dart::dynamics::Joint *j = bh->getJoint((*it));
        j->setActuatorType(dart::dynamics::Joint::FORCE);
     	j->setPositionLimited(true);
        j->setPosition(0, joint_q_map[(*it)]);
    }

    int counter = 0;

    while (ros::ok()) {
        world->step(false);

        for (std::map<std::string, double>::iterator it = joint_q_map.begin(); it != joint_q_map.end(); it++) {
            dart::dynamics::Joint *j = bh->getJoint(it->first);
            it->second = j->getPosition(0);
        }

        gc.controlStep(joint_q_map);

        // Compute the joint forces needed to compensate for Coriolis forces and
        // gravity
        const Eigen::VectorXd& Cg = bh->getCoriolisAndGravityForces();

        for (std::map<std::string, double>::iterator it = joint_q_map.begin(); it != joint_q_map.end(); it++) {
            dart::dynamics::Joint *j = bh->getJoint(it->first);
            int qidx = j->getIndexInSkeleton(0);
            double u = gc.getControl(it->first);
            double dq = j->getVelocity(0);
            if (!gc.isBackdrivable(it->first)) {
                j->setPositionLowerLimit(0, std::max(j->getPositionLowerLimit(0), it->second-0.01));
            }

            if (gc.isStopped(it->first)) {
                j->setPositionLowerLimit(0, std::max(j->getPositionLowerLimit(0), it->second-0.01));
                j->setPositionUpperLimit(0, std::min(j->getPositionUpperLimit(0), it->second+0.01));
//                std::cout << it->first << " " << "stopped" << std::endl;
            }
            j->setForce(0, 0.02*(u-dq) + Cg(qidx));
        }

        for (int bidx = 0; bidx < bh->getNumBodyNodes(); bidx++) {
            dart::dynamics::BodyNode *b = bh->getBodyNode(bidx);
            const Eigen::Isometry3d &tf = b->getTransform();
            KDL::Frame T_W_L;
            EigenTfToKDL(tf, T_W_L);
//            std::cout << b->getName() << std::endl;
            publishTransform(br, T_W_L, b->getName(), "world");
        }

        int m_id = 0;
        for (int bidx = 0; bidx < scene->getNumBodyNodes(); bidx++) {
                dart::dynamics::BodyNode *b = scene->getBodyNode(bidx);

                const Eigen::Isometry3d &tf = b->getTransform();
                KDL::Frame T_W_L;
                EigenTfToKDL(tf, T_W_L);
                publishTransform(br, T_W_L, b->getName(), "world");
                for (int cidx = 0; cidx < b->getNumCollisionShapes(); cidx++) {
                    dart::dynamics::ConstShapePtr sh = b->getCollisionShape(cidx);
                    if (sh->getShapeType() == dart::dynamics::Shape::MESH) {
                        std::shared_ptr<const dart::dynamics::MeshShape > msh = std::static_pointer_cast<const dart::dynamics::MeshShape >(sh);
                        m_id = markers_pub.addMeshMarker(m_id, KDL::Vector(), 0, 1, 0, 1, 1, 1, 1, msh->getMeshUri(), b->getName());
                    }
                }
        }

        markers_pub.publish();

        ros::spinOnce();
        loop_rate.sleep();

        counter++;
        if (counter < 3000) {
        }
        else if (counter == 3000) {
            dart::dynamics::Joint::Properties prop = bh->getJoint(0)->getJointProperties();
            dart::dynamics::FreeJoint::Properties prop_free;
            prop_free.mName = prop_free.mName;
            prop_free.mT_ParentBodyToJoint = prop.mT_ParentBodyToJoint;
            prop_free.mT_ChildBodyToJoint = prop.mT_ChildBodyToJoint;
            prop_free.mIsPositionLimited = false;
            prop_free.mActuatorType = dart::dynamics::Joint::VELOCITY;
            bh->getRootBodyNode()->changeParentJointType<dart::dynamics::FreeJoint >(prop_free);
        }
        else if (counter < 4000) {
            bh->getDof("Joint_pos_z")->setVelocity(-0.1);
        }
        else {
            break;
        }
    }

    //
    // generate models
    //

    const std::string ob_name( "graspable" );

    scene->getBodyNode(ob_name)->setFrictionCoeff(0.001);

    // calculate point clouds for all links and for the grasped object
    std::map<std::string, pcl::PointCloud<pcl::PointNormal>::Ptr > point_clouds_map;
    std::map<std::string, pcl::PointCloud<pcl::PrincipalCurvatures>::Ptr > point_pc_clouds_map;
    std::map<std::string, KDL::Frame > frames_map;
    std::map<std::string, boost::shared_ptr<std::vector<KDL::Frame > > > features_map;
    std::map<std::string, boost::shared_ptr<pcl::VoxelGrid<pcl::PointNormal> > > grids_map;
    for (int skidx = 0; skidx < world->getNumSkeletons(); skidx++) {
        dart::dynamics::SkeletonPtr sk = world->getSkeleton(skidx);

        for (int bidx = 0; bidx < sk->getNumBodyNodes(); bidx++) {
            dart::dynamics::BodyNode *b = sk->getBodyNode(bidx);
            const Eigen::Isometry3d &tf = b->getTransform();
            const std::string &body_name = b->getName();
            if (body_name.find("right_Hand") != 0 && body_name != ob_name) {
                continue;
            }
            KDL::Frame T_W_L;
            EigenTfToKDL(tf, T_W_L);
            std::cout << body_name << "   " << b->getNumCollisionShapes() << std::endl;
            for (int cidx = 0; cidx < b->getNumCollisionShapes(); cidx++) {
                dart::dynamics::ConstShapePtr sh = b->getCollisionShape(cidx);
                if (sh->getShapeType() == dart::dynamics::Shape::MESH) {
                    std::shared_ptr<const dart::dynamics::MeshShape > msh = std::static_pointer_cast<const dart::dynamics::MeshShape >(sh);
                    std::cout << "mesh path: " << msh->getMeshPath() << std::endl;
                    std::cout << "mesh uri: " << msh->getMeshUri() << std::endl;
                    const Eigen::Isometry3d &tf = sh->getLocalTransform();
                    KDL::Frame T_L_S;
                    EigenTfToKDL(tf, T_L_S);
                    KDL::Frame T_S_L = T_L_S.Inverse();

                    const aiScene *sc = msh->getMesh();
                    if (sc->mNumMeshes != 1) {
                        std::cout << "ERROR: sc->mNumMeshes = " << sc->mNumMeshes << std::endl;
                    }
                    int midx = 0;
//                    std::cout << "v: " << sc->mMeshes[midx]->mNumVertices << "   f: " << sc->mMeshes[midx]->mNumFaces << std::endl;
                    pcl::PointCloud<pcl::PointNormal>::Ptr cloud_1 (new pcl::PointCloud<pcl::PointNormal>);
                    uniform_sampling(sc->mMeshes[midx], 1000000, *cloud_1);
                    for (int pidx = 0; pidx < cloud_1->points.size(); pidx++) {
                        KDL::Vector pt_L = T_L_S * KDL::Vector(cloud_1->points[pidx].x, cloud_1->points[pidx].y, cloud_1->points[pidx].z);
                        cloud_1->points[pidx].x = pt_L.x();
                        cloud_1->points[pidx].y = pt_L.y();
                        cloud_1->points[pidx].z = pt_L.z();
                    }
                    // Voxelgrid
                    boost::shared_ptr<pcl::VoxelGrid<pcl::PointNormal> > grid_(new pcl::VoxelGrid<pcl::PointNormal>);
                    pcl::PointCloud<pcl::PointNormal>::Ptr res(new pcl::PointCloud<pcl::PointNormal>);
                    grid_->setDownsampleAllData(true);
                    grid_->setSaveLeafLayout(true);
                    grid_->setInputCloud(cloud_1);
                    grid_->setLeafSize(0.004, 0.004, 0.004);
                    grid_->filter (*res);
                    point_clouds_map[body_name] = res;
                    frames_map[body_name] = T_W_L;
                    grids_map[body_name] = grid_;

                    std::cout << "res->points.size(): " << res->points.size() << std::endl;

                    pcl::search::KdTree<pcl::PointNormal>::Ptr tree (new pcl::search::KdTree<pcl::PointNormal>);

                    // Setup the principal curvatures computation
                    pcl::PrincipalCurvaturesEstimation<pcl::PointNormal, pcl::PointNormal, pcl::PrincipalCurvatures> principalCurvaturesEstimation;

                    // Provide the original point cloud (without normals)
                    principalCurvaturesEstimation.setInputCloud (res);

                    // Provide the point cloud with normals
                    principalCurvaturesEstimation.setInputNormals(res);

                    // Use the same KdTree from the normal estimation
                    principalCurvaturesEstimation.setSearchMethod (tree);
                    principalCurvaturesEstimation.setRadiusSearch(0.02);

                    // Actually compute the principal curvatures
                    pcl::PointCloud<pcl::PrincipalCurvatures>::Ptr principalCurvatures (new pcl::PointCloud<pcl::PrincipalCurvatures> ());
                    principalCurvaturesEstimation.compute (*principalCurvatures);
                    point_pc_clouds_map[body_name] = principalCurvatures;

                    features_map[body_name].reset( new std::vector<KDL::Frame >(res->points.size()) );
                    for (int pidx = 0; pidx < res->points.size(); pidx++) {
                        KDL::Vector nx, ny, nz(res->points[pidx].normal[0], res->points[pidx].normal[1], res->points[pidx].normal[2]);
                        if ( std::fabs( principalCurvatures->points[pidx].pc1 - principalCurvatures->points[pidx].pc2 ) > 0.001) {
                            nx = KDL::Vector(principalCurvatures->points[pidx].principal_curvature[0], principalCurvatures->points[pidx].principal_curvature[1], principalCurvatures->points[pidx].principal_curvature[2]);
                        }
                        else {
                            if (std::fabs(nz.z()) < 0.7) {
                                nx = KDL::Vector(0, 0, 1);
                            }
                            else {
                                nx = KDL::Vector(1, 0, 0);
                            }
                        }
                        ny = nz * nx;
                        nx = ny * nz;
                        nx.Normalize();
                        ny.Normalize();
                        nz.Normalize();
                        (*features_map[body_name])[pidx] = KDL::Frame( KDL::Rotation(nx, ny, nz), KDL::Vector(res->points[pidx].x, res->points[pidx].y, res->points[pidx].z) );
                    }
                }
            }
        }
    }

    const double sigma_p = 0.01;//05;
    const double sigma_q = 10.0/180.0*PI;//100.0;
    const double sigma_r = 0.2;//05;
    double sigma_c = 5.0/180.0*PI;

    int m_id = 101;

    // generate object model
    boost::shared_ptr<ObjectModel > om(new ObjectModel);
    for (int pidx = 0; pidx < point_clouds_map[ob_name]->points.size(); pidx++) {
        if (point_pc_clouds_map[ob_name]->points[pidx].pc1 > 1.1 * point_pc_clouds_map[ob_name]->points[pidx].pc2) {
            // e.g. pc1=1, pc2=0
            // edge
            om->addPointFeature((*features_map[ob_name])[pidx] * KDL::Frame(KDL::Rotation::RotZ(PI)), point_pc_clouds_map[ob_name]->points[pidx].pc1, point_pc_clouds_map[ob_name]->points[pidx].pc2);
            om->addPointFeature((*features_map[ob_name])[pidx], point_pc_clouds_map[ob_name]->points[pidx].pc1, point_pc_clouds_map[ob_name]->points[pidx].pc2);
        }
        else {
            for (double angle = 0.0; angle < 359.0/180.0*PI; angle += 20.0/180.0*PI) {
                om->addPointFeature((*features_map[ob_name])[pidx] * KDL::Frame(KDL::Rotation::RotZ(angle)), point_pc_clouds_map[ob_name]->points[pidx].pc1, point_pc_clouds_map[ob_name]->points[pidx].pc2);
            }
        }
    }


    std::cout << "om.getPointFeatures().size(): " << om->getPointFeatures().size() << std::endl;
    KDL::Frame T_W_O = frames_map[ob_name];

    // generate collision model
    std::map<std::string, std::list<std::pair<int, double> > > link_pt_map;
    boost::shared_ptr<CollisionModel > cm(new CollisionModel);
    cm->setSamplerParameters(sigma_p, sigma_q, sigma_r);

    std::list<std::string > gripper_link_names;
    for (int bidx = 0; bidx < bh->getNumBodyNodes(); bidx++) {
        const std::string &link_name = bh->getBodyNode(bidx)->getName();
        gripper_link_names.push_back(link_name);
    }

    double dist_range = 0.01;
    for (std::list<std::string >::const_iterator nit = gripper_link_names.begin(); nit != gripper_link_names.end(); nit++) {
        const std::string &link_name = (*nit);
        if (point_clouds_map.find( link_name ) == point_clouds_map.end()) {
            continue;
        }
        cm->addLinkContacts(dist_range, link_name, point_clouds_map[link_name], frames_map[link_name],
                            om->getPointFeatures(), T_W_O);
    }

    // generate hand configuration model
    boost::shared_ptr<HandConfigurationModel > hm(new HandConfigurationModel);
    std::map<std::string, double> joint_q_map_before( joint_q_map );

    double angleDiffKnuckleTwo = 15.0/180.0*PI;
    joint_q_map_before["right_HandFingerOneKnuckleTwoJoint"] -= angleDiffKnuckleTwo;
    joint_q_map_before["right_HandFingerTwoKnuckleTwoJoint"] -= angleDiffKnuckleTwo;
    joint_q_map_before["right_HandFingerThreeKnuckleTwoJoint"] -= angleDiffKnuckleTwo;
    joint_q_map_before["right_HandFingerOneKnuckleThreeJoint"] -= angleDiffKnuckleTwo*0.333333;
    joint_q_map_before["right_HandFingerTwoKnuckleThreeJoint"] -= angleDiffKnuckleTwo*0.333333;
    joint_q_map_before["right_HandFingerThreeKnuckleThreeJoint"] -= angleDiffKnuckleTwo*0.333333;

    hm->generateModel(joint_q_map_before, joint_q_map, 1.0, 10, sigma_c);

    writeToXml(argv[3], cm, hm);

    return 0;
}
Ejemplo n.º 6
0
// Add all methods from the provides list of the given entity into lists in the
// given symbol table.
static bool collate_provided(ast_t* entity, methods_t* method_info)
{
  assert(entity != NULL);

  bool r = true;
  ast_t* traits = ast_childidx(entity, 3);

  for(ast_t* t = ast_child(traits); t != NULL; t = ast_sibling(t))
  {
    assert(ast_id(t) == TK_NOMINAL);
    ast_t* trait_def = (ast_t*)ast_data(t);
    assert(trait_def != NULL);

    // TODO: Check whether we need an error here
    if((ast_id(trait_def) != TK_TRAIT) && (ast_id(trait_def) != TK_INTERFACE))
      return false;

    // Check for duplicates in our provides list
    // This is just simple compare of each entry against all the other. This is
    // clearly O(n^2), but since provides lists are likely to be small that
    // should be OK. If it turns out to be a problem it can be changed later.
    for(ast_t* p = ast_child(traits); p != t; p = ast_sibling(p))
    {
      if(trait_def == (ast_t*)ast_data(p))
      {
        ast_error(t, "duplicate entry in provides list");
        ast_error(p, "previous entry here");
      }
    }

    if(!build_entity_def(trait_def))
      return false;

    ast_t* type_params = ast_childidx(trait_def, 1);
    ast_t* type_args = ast_childidx(t, 2);
    ast_t* trait_methods = ast_childidx(trait_def, 4);

    for(ast_t* m = ast_child(trait_methods); m != NULL; m = ast_sibling(m))
    {
      // Reify the method with the type parameters from trait definition and
      // the reified type arguments from trait reference
      ast_t* r_method = reify(m, type_params, type_args);
      const char* entity_name = ast_name(ast_child(entity));

      if(ast_id(r_method) == TK_BE || ast_id(r_method) == TK_NEW)
      {
        // Modify return type to the inheritting type
        ast_t* ret_type = ast_childidx(r_method, 4);
        assert(ast_id(ret_type) == TK_NOMINAL);

        const char* pkg_name = package_name(ast_nearest(entity, TK_PACKAGE));
        ast_set_name(ast_childidx(ret_type, 0), pkg_name);
        ast_set_name(ast_childidx(ret_type, 1), entity_name);
      }

      if(!add_method_to_list(r_method, method_info, entity_name))
        r = false;
    }
  }

  return r;
}
Ejemplo n.º 7
0
/** \brief Parse a line from a version entry.
 *
 * This function reads the header (one line), a list of logs, and then
 * the footer of a version entry.
 *
 * If a version exists, even if it is wrong, the function returns true.
 * The function returns false if the end of the file is reached.
 *
 * \param[in] s  The state to read from.
 *
 * \return true if the end of the file was not yet reached when this
 *         version was read in full.
 */
bool changelog_file::version::parse(state& s)
{
    f_filename = s.get_filename();
    f_line = s.get_line();

    // the current line must be the header
    if(s.space_count() != 0)
    {
        wpkg_output::log("changelog:%1:%2: a changelog version entry must start with a valid header")
                .arg(f_filename)
                .arg(f_line)
            .level(wpkg_output::level_error)
            .module(wpkg_output::module_build_package)
            .action("changelog");
        return s.next_line();
    }

    bool good_header(true);
    const std::string& header(s.last_line());
    const char *h(header.c_str());
    const char *start(h);

    // *** Package Name ***
    for(; !isspace(*h) && *h != '('; ++h)
    {
        if(*h == '\0')
        {
            wpkg_output::log("changelog:%1:%2: invalid header, expected the project name, version, distributions, and urgency information")
                    .arg(f_filename)
                    .arg(f_line)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .action("changelog");
            good_header = false;
            break;
        }
    }
    if(good_header)
    {
        std::string package_name(start, h - start);
        if(!wpkg_util::is_package_name(package_name))
        {
            wpkg_output::log("changelog:%1:%2: the package name %3 is not valid")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(package_name)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .action("changelog");
        }
        else
        {
            f_package = package_name;
        }

        if(!isspace(*h))
        {
            // this is just a warning, but the user is expected to put a space
            // after the package name and before the version
            wpkg_output::log("changelog:%1:%2: the package name %3 is not followed by a space before the version information")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(package_name)
                .level(wpkg_output::level_warning)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
    }

    // *** Version ***
    if(good_header)
    {
        for(; isspace(*h); ++h);

        if(*h != '(')
        {
            wpkg_output::log("changelog:%1:%2: invalid header, expected the version between parenthesis after the package name")
                    .arg(f_filename)
                    .arg(f_line)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
    }
    if(good_header)
    {
        // read the version
        ++h;
        start = h;
        for(; !isspace(*h) && *h != ')' && *h != '\0'; ++h);

        std::string version_str(start, h - start);
        char err[256];
        if(!validate_debian_version(version_str.c_str(), err, sizeof(err)))
        {
            wpkg_output::log("control:%1:%2: %3 is not a valid Debian version")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(version_str)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_changelog)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
        else
        {
            f_version = version_str;
        }
    }
    if(good_header)
    {
        if(isspace(*h))
        {
            for(; isspace(*h); ++h);
            wpkg_output::log("control:%1:%2: version %3 is not immediately followed by a closing parenthesis")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(f_version)
                .level(wpkg_output::level_warning)
                .module(wpkg_output::module_changelog)
                .package(f_package)
                .action("changelog");
        }
        if(*h != ')')
        {
            wpkg_output::log("control:%1:%2: version %3 is not followed by a closing parenthesis: ')'")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(f_version)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_changelog)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
    }

    // *** Distributions ***
    if(good_header)
    {
        // the first ++h is to skip the ')' from the version
        for(++h; isspace(*h); ++h);
        do
        {
            start = h;
            for(; !isspace(*h) && *h != '\0' && *h != ';' && *h != ','; ++h);
            std::string d(start, h - start);
            wpkg_filename::uri_filename distribution(d);
            if(distribution.is_absolute())
            {
                wpkg_output::log("control:%1:%2: a distribution must be a relative path, %3 is not acceptable")
                        .arg(f_filename)
                        .arg(f_line)
                        .quoted_arg(distribution)
                    .level(wpkg_output::level_error)
                    .module(wpkg_output::module_changelog)
                    .package(f_package)
                    .action("changelog");
                good_header = false;
            }
            else if(distribution.segment_size() < 1)
            {
                // This happens if no distribution is specified
                wpkg_output::log("control:%1:%2: a distribution cannot be the empty string")
                        .arg(f_filename)
                        .arg(f_line)
                    .level(wpkg_output::level_error)
                    .module(wpkg_output::module_changelog)
                    .package(f_package)
                    .action("changelog");
                good_header = false;
            }
            else
            {
                f_distributions.push_back(distribution.original_filename());
            }
            for(; isspace(*h); ++h);
        }
        while(*h != '\0' && *h != ';' && *h != ',');
    }
    // We want to support more than one in source packages, that way a package
    // can be part of stable and unstable (because we view our distributions
    // as separate entities rather than complements.)
    //if(good_header)
    //{
    //    if(f_distributions.size() > 1)
    //    {
    //        wpkg_output::log("control:%1:%2: although the syntax allows for more than one distribution, we do not support more than one at this time")
    //                .arg(f_filename)
    //                .arg(f_line)
    //            .level(wpkg_output::level_error)
    //            .module(wpkg_output::module_changelog)
    //            .package(f_package)
    //            .action("changelog");
    //        good_header = false;
    //    }
    //}

    // *** Parameters ***
    if(good_header)
    {
        for(; isspace(*h); ++h);

        if(*h != ';')
        {
            wpkg_output::log("changelog:%1:%2: invalid header, expected the list of distributions to end with ';'")
                    .arg(f_filename)
                    .arg(f_line)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
        else
        {
            for(++h; isspace(*h); ++h);
        }
    }
    while(good_header && *h != '\0')
    {
        start = h;
        const char *e(h);
        const char *equal(NULL);
        for(; *h != ',' && *h != '\0'; ++h)
        {
            if(!isspace(*h))
            {
                e = h + 1;
            }
            if(*h == '=')
            {
                equal = h;
            }
        }
        if(equal == NULL)
        {
            wpkg_output::log("changelog:%1:%2: invalid header, parameter %3 is expected to include an equal sign (=) after the parameter name")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(std::string(start, h - start))
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
        else if(start == equal)
        {
            wpkg_output::log("changelog:%1:%2: invalid header, parameter %3 is missing a name before the equal character")
                    .arg(f_filename)
                    .arg(f_line)
                    .quoted_arg(std::string(start, h - start))
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_header = false;
        }
        else
        {
            std::string name(start, equal - start);
            if(f_parameters.find(name) != f_parameters.end())
            {
                wpkg_output::log("changelog:%1:%2: invalid header, parameter %3 is defined twice")
                        .arg(f_filename)
                        .arg(f_line)
                        .quoted_arg(name)
                    .level(wpkg_output::level_error)
                    .module(wpkg_output::module_build_package)
                    .package(f_package)
                    .action("changelog");
                good_header = false;
            }
            else
            {
                ++equal;
                std::string value(equal, e - equal);
                f_parameters[name] = value;
            }
        }

        // skip commas and spaces and repeat for next parameter
        for(; *h == ',' || isspace(*h); ++h);
    }

    // We got the header, now we check for the list of logs
    // the log::parse() function is expected to return false
    // once we reach the end of that list, then we must find
    // a footer that starts with a space and two dashes

    if(!s.next_line())
    {
        wpkg_output::log("changelog:%1:%2: every changelog version entry must have at least one log and end with a valid footer")
                .arg(f_filename)
                .arg(s.get_line())
            .level(wpkg_output::level_error)
            .module(wpkg_output::module_build_package)
            .package(f_package)
            .action("changelog");
        return false;
    }

    bool group(true);
    for(;;)
    {
        log l;
        if(!l.parse(s, group))
        {
            break;
        }
        f_logs.push_back(l);
    }

    // we are at the end of the log stream for this version entry,
    // there has to be a valid footer now

    bool good_footer(true);

    if(s.space_count() != 1)
    {
        wpkg_output::log("changelog:%1:%2: a changelog version entry must end with a valid footer, which must start with exactly one space")
                .arg(f_filename)
                .arg(s.get_line())
            .level(wpkg_output::level_error)
            .module(wpkg_output::module_build_package)
            .package(f_package)
            .action("changelog");
        good_footer = false;
    }

    const std::string& footer(s.last_line());
    const char *f(footer.c_str());

    if(good_footer)
    {
        if(f[0] != '-' || f[1] != '-' || f[2] != ' ')
        {
            wpkg_output::log("changelog:%1:%2: a changelog version entry must end with a valid footer, which must start with two dashes")
                    .arg(f_filename)
                    .arg(s.get_line())
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_footer = false;
        }
    }

    if(good_footer)
    {
        // search for two spaces to break the maintainer name/email and date
        f += 3;
        start = f;
        for(; f[0] != '\0' && (f[0] != ' ' || f[1] != ' '); ++f);
        std::string maintainer(start, f - start);

        // TODO: use libtld to verify email

        f_maintainer = maintainer;

        std::string date(f + 2);
        struct tm time_info;
        if(strptime(date.c_str(), "%a, %d %b %Y %H:%M:%S %z", &time_info) == NULL)
        {
            wpkg_output::log("changelog:%1:%2: the footer in this changelog version entry has an invalid date: %3")
                    .arg(f_filename)
                    .arg(s.get_line())
                    .quoted_arg(date)
                .level(wpkg_output::level_error)
                .module(wpkg_output::module_build_package)
                .package(f_package)
                .action("changelog");
            good_footer = false;
        }
        else
        {
            f_date = date;
        }
    }

    // do not read another line in case this one is the next header
    return true;
}