Skip to content

Commit

Permalink
reflow/syntax: add range builtin
Browse files Browse the repository at this point in the history
Summary:
Range allows the user to generate lists of indices, e.g.:

	range(1, 5) == [1,2,3,4]

Reviewers: pgopal, pknudsgaard

Reviewed By: pknudsgaard

Differential Revision: https://phabricator.grailbio.com/D10005

fbshipit-source-id: 6f5ec00
  • Loading branch information
mariusae authored and grailbot committed Feb 2, 2018
1 parent 9264905 commit 9f09974
Show file tree
Hide file tree
Showing 7 changed files with 2,941 additions and 2,656 deletions.
14 changes: 14 additions & 0 deletions syntax/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
var (
coerceExecOutputDigest = reflow.Digester.FromString("grail.com/reflow/syntax.Eval.coerceExecOutput")
sequenceDigest = reflow.Digester.FromString("grail.com/reflow/syntax.Eval.~>")

one = big.NewInt(1)
)

// Eval evaluates the expression e and returns its value (or error).
Expand Down Expand Up @@ -637,6 +639,18 @@ func (e *Expr) eval(sess *Session, env *values.Env, ident string) (val values.T,
fmt.Fprintf(os.Stderr, "%s%s: %s\n", e.Position, ident, values.Sprint(vs[0], e.Left.Type))
return vs[0], nil
}, tval{e.Left.Type, left})
case "range":
return e.k(sess, env, ident, func(vs []values.T) (values.T, error) {
left, right := vs[0].(*big.Int), vs[1].(*big.Int)
if left.Cmp(right) > 0 {
return nil, errors.New("invalid range")
}
var list values.List
for i := new(big.Int).Set(left); i.Cmp(right) < 0; i.Add(i, one) {
list = append(list, new(big.Int).Set(i))
}
return list, nil
}, e.Left, e.Right)
}
case ExprRequires:
req, err := e.evalRequirements(sess, env, ident)
Expand Down
14 changes: 11 additions & 3 deletions syntax/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,14 @@ func (e *Expr) init(sess *Session, env *types.Env) {
e.Type = e.Left.Type.Assign(nil)
case "trace":
e.Type = e.Left.Type.Assign(nil)
case "range":
if e.Left.Type.Kind != types.IntKind {
e.Type = types.Errorf("range expects an integer, not %s", e.Left.Type)
} else if e.Right.Type.Kind != types.IntKind {
e.Type = types.Errorf("range expects an integer, not %s", e.Right.Type)
} else {
e.Type = types.List(types.Int)
}
}
case ExprRequires:
if err := e.initResources(sess, env); err != nil {
Expand Down Expand Up @@ -1056,9 +1064,9 @@ func (e *Expr) String() string {
var binopPrec = map[string]int{
"||": 2,
"&&": 3,
"<": 4, ">": 4, "<=": 4, ">=": 4, "!=": 4, "==": 4,
"+": 5, "-": 5, "|": 5, "^": 5,
"*": 6, "/": 6, "%": 6, "&": 6, "<<": 6, ">>": 6,
"<": 5, ">": 5, "<=": 5, ">=": 5, "!=": 5, "==": 5,
"+": 6, "-": 6, "|": 6, "^": 6,
"*": 7, "/": 7, "%": 7, "&": 7, "<<": 7, ">>": 7,
}

// Prec returns the precedence of expression e. If it is not a binary
Expand Down
2 changes: 2 additions & 0 deletions syntax/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ var identTokens = map[string]int{

"type": tokType,

"range": tokRange,

// Reserved identifiers:
"force": tokReserved,
"switch": tokReserved,
Expand Down
4 changes: 3 additions & 1 deletion syntax/reflow.y
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type typearg struct {
%token <pos> tokVal tokFunc tokAssign tokArrow tokLeftArrow tokIf tokElse
%token <pos> tokMake tokLen tokPanic tokDelay tokTrace tokMap tokList tokZip tokUnzip tokFlatten
%token <pos> tokStartModule tokStartDecls tokStartExpr tokStartType
%token <pos> tokKeyspace tokParam tokEllipsis tokReserved tokRequires
%token <pos> tokKeyspace tokParam tokEllipsis tokReserved tokRequires tokRange
%token <pos> tokType
%token <pos> '{' '(' '['
%token <pos> tokOrOr tokAndAnd tokLE tokGE tokNE tokEqEq tokLSH tokRSH
Expand Down Expand Up @@ -558,6 +558,8 @@ term:
{$$ = &Expr{Position: $1.Position, Comment: $1.comment, Kind: ExprBuiltin, Op: "flatten", Left: $3}}
| tokMap '(' expr ')'
{$$ = &Expr{Position: $1.Position, Comment: $1.comment, Kind: ExprBuiltin, Op: "map", Left: $3}}
| tokRange '(' expr ',' expr ')'
{$$ = &Expr{Position: $1.Position, Comment: $1.comment, Kind: ExprBuiltin, Op: "range", Left: $3, Right: $5}}
| tokList '(' expr ')'
{$$ = &Expr{Position: $1.Position, Comment: $1.comment, Kind: ExprBuiltin, Op: "list", Left: $3}}
| tokDelay '(' expr ')'
Expand Down
5 changes: 5 additions & 0 deletions syntax/testdata/test1.rf
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,8 @@ val TestCommaOks = {
)
true
}

val TestRange = {
func eq(x, y [int]) bool = test.All([x == y | (x, y) <- zip(x, y)])
eq(range(1, 2), [1]) && eq(range(0, 4), [0,1,2,3]) && len(range(0, 5000)) == 5000
}
Loading

0 comments on commit 9f09974

Please sign in to comment.