* Generalised the dependencyClosure primop to builtins.genericClosure,
which is hopefully more useful. * New primops: length, mul, div.
This commit is contained in:
		
							parent
							
								
									d567baabbd
								
							
						
					
					
						commit
						7cd88b1dec
					
				
					 5 changed files with 442 additions and 139 deletions
				
			
		| 
						 | 
				
			
			@ -128,59 +128,7 @@ static Expr prim_isFunction(EvalState & state, const ATermVector & args)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static Path findDependency(Path dir, string dep)
 | 
			
		||||
{
 | 
			
		||||
    if (dep[0] == '/') throw EvalError(
 | 
			
		||||
        format("illegal absolute dependency `%1%'") % dep);
 | 
			
		||||
 | 
			
		||||
    Path p = canonPath(dir + "/" + dep);
 | 
			
		||||
 | 
			
		||||
    if (pathExists(p))
 | 
			
		||||
        return p;
 | 
			
		||||
    else
 | 
			
		||||
        return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Make path `p' relative to directory `pivot'.  E.g.,
 | 
			
		||||
   relativise("/a/b/c", "a/b/x/y") => "../x/y".  Both input paths
 | 
			
		||||
   should be in absolute canonical form. */
 | 
			
		||||
static string relativise(Path pivot, Path p)
 | 
			
		||||
{
 | 
			
		||||
    assert(pivot.size() > 0 && pivot[0] == '/');
 | 
			
		||||
    assert(p.size() > 0 && p[0] == '/');
 | 
			
		||||
        
 | 
			
		||||
    if (pivot == p) return ".";
 | 
			
		||||
 | 
			
		||||
    /* `p' is in `pivot'? */
 | 
			
		||||
    Path pivot2 = pivot + "/";
 | 
			
		||||
    if (p.substr(0, pivot2.size()) == pivot2) {
 | 
			
		||||
        return p.substr(pivot2.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Otherwise, `p' is in a parent of `pivot'.  Find up till which
 | 
			
		||||
       path component `p' and `pivot' match, and add an appropriate
 | 
			
		||||
       number of `..' components. */
 | 
			
		||||
    string::size_type i = 1;
 | 
			
		||||
    while (1) {
 | 
			
		||||
        string::size_type j = pivot.find('/', i);
 | 
			
		||||
        if (j == string::npos) break;
 | 
			
		||||
        j++;
 | 
			
		||||
        if (pivot.substr(0, j) != p.substr(0, j)) break;
 | 
			
		||||
        i = j;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    string prefix;
 | 
			
		||||
    unsigned int slashes = count(pivot.begin() + i, pivot.end(), '/') + 1;
 | 
			
		||||
    while (slashes--) {
 | 
			
		||||
        prefix += "../";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return prefix + p.substr(i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static Expr prim_dependencyClosure(EvalState & state, const ATermVector & args)
 | 
			
		||||
static Expr prim_genericClosure(EvalState & state, const ATermVector & args)
 | 
			
		||||
{
 | 
			
		||||
    startNest(nest, lvlDebug, "finding dependencies");
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -191,87 +139,40 @@ static Expr prim_dependencyClosure(EvalState & state, const ATermVector & args)
 | 
			
		|||
    if (!startSet) throw EvalError("attribute `startSet' required");
 | 
			
		||||
    ATermList startSet2 = evalList(state, startSet);
 | 
			
		||||
 | 
			
		||||
    Path pivot;
 | 
			
		||||
    PathSet workSet;
 | 
			
		||||
    for (ATermIterator i(startSet2); i; ++i) {
 | 
			
		||||
        PathSet context; /* !!! what to do? */
 | 
			
		||||
        Path p = coerceToPath(state, *i, context);
 | 
			
		||||
        workSet.insert(p);
 | 
			
		||||
        pivot = dirOf(p);
 | 
			
		||||
    }
 | 
			
		||||
    set<Expr> workSet; // !!! gc roots
 | 
			
		||||
    for (ATermIterator i(startSet2); i; ++i) workSet.insert(*i);
 | 
			
		||||
 | 
			
		||||
    /* Get the search path. */
 | 
			
		||||
    PathSet searchPath;
 | 
			
		||||
    Expr e = queryAttr(attrs, "searchPath");
 | 
			
		||||
    if (e) {
 | 
			
		||||
        ATermList list = evalList(state, e);
 | 
			
		||||
        for (ATermIterator i(list); i; ++i) {
 | 
			
		||||
            PathSet context; /* !!! what to do? */
 | 
			
		||||
            Path p = coerceToPath(state, *i, context);
 | 
			
		||||
            searchPath.insert(p);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Expr scanner = queryAttr(attrs, "scanner");
 | 
			
		||||
    if (!scanner) throw EvalError("attribute `scanner' required");
 | 
			
		||||
    /* Get the operator. */
 | 
			
		||||
    Expr op = queryAttr(attrs, "operator");
 | 
			
		||||
    if (!op) throw EvalError("attribute `operator' required");
 | 
			
		||||
    
 | 
			
		||||
    /* Construct the dependency closure by querying the dependency of
 | 
			
		||||
       each path in `workSet', adding the dependencies to
 | 
			
		||||
       `workSet'. */
 | 
			
		||||
    PathSet doneSet;
 | 
			
		||||
    /* Construct the closure by applying the operator to element of
 | 
			
		||||
       `workSet', adding the result to `workSet', continuing until
 | 
			
		||||
       no new elements are found. */
 | 
			
		||||
    ATermList res = ATempty;
 | 
			
		||||
    set<Expr> doneKeys; // !!! gc roots
 | 
			
		||||
    while (!workSet.empty()) {
 | 
			
		||||
	Path path = *(workSet.begin());
 | 
			
		||||
	workSet.erase(path);
 | 
			
		||||
	Expr e = *(workSet.begin());
 | 
			
		||||
	workSet.erase(e);
 | 
			
		||||
 | 
			
		||||
	if (doneSet.find(path) != doneSet.end()) continue;
 | 
			
		||||
        doneSet.insert(path);
 | 
			
		||||
        e = strictEvalExpr(state, e);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            
 | 
			
		||||
            /* Call the `scanner' function with `path' as argument. */
 | 
			
		||||
            debug(format("finding dependencies in `%1%'") % path);
 | 
			
		||||
            ATermList deps = evalList(state, makeCall(scanner, makeStr(path)));
 | 
			
		||||
        Expr key = queryAttr(e, "key");
 | 
			
		||||
        if (!key) throw EvalError("attribute `key' required");
 | 
			
		||||
 | 
			
		||||
            /* Try to find the dependencies relative to the `path'. */
 | 
			
		||||
            for (ATermIterator i(deps); i; ++i) {
 | 
			
		||||
                string s = evalStringNoCtx(state, *i);
 | 
			
		||||
                
 | 
			
		||||
                Path dep = findDependency(dirOf(path), s);
 | 
			
		||||
	if (doneKeys.find(key) != doneKeys.end()) continue;
 | 
			
		||||
        doneKeys.insert(key);
 | 
			
		||||
        res = ATinsert(res, e);
 | 
			
		||||
        
 | 
			
		||||
        /* Call the `operator' function with `e' as argument. */
 | 
			
		||||
        ATermList res = evalList(state, makeCall(op, e));
 | 
			
		||||
 | 
			
		||||
                if (dep == "") {
 | 
			
		||||
                    for (PathSet::iterator j = searchPath.begin();
 | 
			
		||||
                         j != searchPath.end(); ++j)
 | 
			
		||||
                    {
 | 
			
		||||
                        dep = findDependency(*j, s);
 | 
			
		||||
                        if (dep != "") break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (dep == "")
 | 
			
		||||
                    debug(format("did NOT find dependency `%1%'") % s);
 | 
			
		||||
                else {
 | 
			
		||||
                    debug(format("found dependency `%1%'") % dep);
 | 
			
		||||
                    workSet.insert(dep);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } catch (Error & e) {
 | 
			
		||||
            e.addPrefix(format("while finding dependencies in `%1%':\n")
 | 
			
		||||
                % path);
 | 
			
		||||
            throw;
 | 
			
		||||
        }
 | 
			
		||||
        /* Try to find the dependencies relative to the `path'. */
 | 
			
		||||
        for (ATermIterator i(res); i; ++i)
 | 
			
		||||
            workSet.insert(evalExpr(state, *i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Return a list of the dependencies we've just found. */
 | 
			
		||||
    ATermList deps = ATempty;
 | 
			
		||||
    for (PathSet::iterator i = doneSet.begin(); i != doneSet.end(); ++i) {
 | 
			
		||||
        deps = ATinsert(deps, makeStr(relativise(pivot, *i)));
 | 
			
		||||
        deps = ATinsert(deps, makeStr(*i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debug(format("dependency list is `%1%'") % makeList(deps));
 | 
			
		||||
    
 | 
			
		||||
    return makeList(deps);
 | 
			
		||||
    return makeList(res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -311,15 +212,6 @@ static Expr prim_trace(EvalState & state, const ATermVector & args)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static Expr prim_relativise(EvalState & state, const ATermVector & args)
 | 
			
		||||
{
 | 
			
		||||
    PathSet context; /* !!! what to do? */
 | 
			
		||||
    Path pivot = coerceToPath(state, args[0], context);
 | 
			
		||||
    Path path = coerceToPath(state, args[1], context);
 | 
			
		||||
    return makeStr(relativise(pivot, path));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************
 | 
			
		||||
 * Derivations
 | 
			
		||||
 *************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -874,6 +766,14 @@ static Expr prim_map(EvalState & state, const ATermVector & args)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Return the length of a list.  This is an O(1) time operation. */
 | 
			
		||||
static Expr prim_length(EvalState & state, const ATermVector & args)
 | 
			
		||||
{
 | 
			
		||||
    ATermList list = evalList(state, args[0]);
 | 
			
		||||
    return makeInt(ATgetLength(list));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*************************************************************
 | 
			
		||||
 * Integer arithmetic
 | 
			
		||||
 *************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -895,6 +795,23 @@ static Expr prim_sub(EvalState & state, const ATermVector & args)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static Expr prim_mul(EvalState & state, const ATermVector & args)
 | 
			
		||||
{
 | 
			
		||||
    int i1 = evalInt(state, args[0]);
 | 
			
		||||
    int i2 = evalInt(state, args[1]);
 | 
			
		||||
    return makeInt(i1 * i2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static Expr prim_div(EvalState & state, const ATermVector & args)
 | 
			
		||||
{
 | 
			
		||||
    int i1 = evalInt(state, args[0]);
 | 
			
		||||
    int i2 = evalInt(state, args[1]);
 | 
			
		||||
    if (i2 == 0) throw EvalError("division by zero");
 | 
			
		||||
    return makeInt(i1 / i2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static Expr prim_lessThan(EvalState & state, const ATermVector & args)
 | 
			
		||||
{
 | 
			
		||||
    int i1 = evalInt(state, args[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -1019,7 +936,7 @@ void EvalState::addPrimOps()
 | 
			
		|||
    addPrimOp("import", 1, prim_import);
 | 
			
		||||
    addPrimOp("isNull", 1, prim_isNull);
 | 
			
		||||
    addPrimOp("__isFunction", 1, prim_isFunction);
 | 
			
		||||
    addPrimOp("dependencyClosure", 1, prim_dependencyClosure);
 | 
			
		||||
    addPrimOp("__genericClosure", 1, prim_genericClosure);
 | 
			
		||||
    addPrimOp("abort", 1, prim_abort);
 | 
			
		||||
    addPrimOp("throw", 1, prim_throw);
 | 
			
		||||
    addPrimOp("__getEnv", 1, prim_getEnv);
 | 
			
		||||
| 
						 | 
				
			
			@ -1029,8 +946,6 @@ void EvalState::addPrimOps()
 | 
			
		|||
    addPrimOp("__exprToString", 1, prim_exprToString);
 | 
			
		||||
    addPrimOp("__stringToExpr", 1, prim_stringToExpr);
 | 
			
		||||
 | 
			
		||||
    addPrimOp("relativise", 2, prim_relativise);
 | 
			
		||||
 | 
			
		||||
    // Derivations
 | 
			
		||||
    addPrimOp("derivation!", 1, prim_derivationStrict);
 | 
			
		||||
    addPrimOp("derivation", 1, prim_derivationLazy);
 | 
			
		||||
| 
						 | 
				
			
			@ -1060,10 +975,13 @@ void EvalState::addPrimOps()
 | 
			
		|||
    addPrimOp("__head", 1, prim_head);
 | 
			
		||||
    addPrimOp("__tail", 1, prim_tail);
 | 
			
		||||
    addPrimOp("map", 2, prim_map);
 | 
			
		||||
    addPrimOp("__length", 1, prim_length);
 | 
			
		||||
 | 
			
		||||
    // Integer arithmetic
 | 
			
		||||
    addPrimOp("__add", 2, prim_add);
 | 
			
		||||
    addPrimOp("__sub", 2, prim_sub);
 | 
			
		||||
    addPrimOp("__mul", 2, prim_mul);
 | 
			
		||||
    addPrimOp("__div", 2, prim_div);
 | 
			
		||||
    addPrimOp("__lessThan", 2, prim_lessThan);
 | 
			
		||||
 | 
			
		||||
    // String manipulation
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue