1// Copyright 2018 The OPA Authors.  All rights reserved.
2// Use of this source code is governed by an Apache2
3// license that can be found in the LICENSE file.op
4
5package ast
6
7import (
8	"bytes"
9	"encoding/json"
10	"fmt"
11	"math/big"
12)
13
14const (
15	// commentsKey is the global map key for the comments slice.
16	commentsKey = "comments"
17
18	// filenameKey is the global map key for the filename.
19	filenameKey = "filename"
20)
21
22type program struct {
23	buf      []interface{}
24	comments interface{}
25}
26
27type ruleExt struct {
28	loc  *Location
29	term *Term
30	body Body
31}
32
33// currentLocation converts the parser context to a Location object.
34func currentLocation(c *current) *Location {
35	return NewLocation(c.text, c.globalStore[filenameKey].(string), c.pos.line, c.pos.col)
36}
37
38func makeProgram(c *current, vals interface{}) (interface{}, error) {
39	var buf []interface{}
40	if vals == nil {
41		return buf, nil
42	}
43	ifaceSlice := vals.([]interface{})
44	head := ifaceSlice[0]
45	buf = append(buf, head)
46	for _, tail := range ifaceSlice[1].([]interface{}) {
47		stmt := tail.([]interface{})[1]
48		buf = append(buf, stmt)
49	}
50	return program{buf, c.globalStore[commentsKey]}, nil
51}
52
53func makePackage(loc *Location, value interface{}) (interface{}, error) {
54	// All packages are implicitly declared under the default root document.
55	term := value.(*Term)
56	path := Ref{DefaultRootDocument.Copy().SetLocation(term.Location)}
57	switch v := term.Value.(type) {
58	case Ref:
59		// Convert head of package Ref to String because it will be prefixed
60		// with the root document variable.
61		head := StringTerm(string(v[0].Value.(Var))).SetLocation(v[0].Location)
62		tail := v[1:]
63		if !tail.IsGround() {
64			return nil, fmt.Errorf("package name cannot contain variables: %v", v)
65		}
66
67		// We do not allow non-string values in package names.
68		// Because documents are typically represented as JSON, non-string keys are
69		// not allowed for now.
70		// TODO(tsandall): consider special syntax for namespacing under arrays.
71		for _, p := range tail {
72			_, ok := p.Value.(String)
73			if !ok {
74				return nil, fmt.Errorf("package name cannot contain non-string values: %v", v)
75			}
76		}
77		path = append(path, head)
78		path = append(path, tail...)
79	case Var:
80		s := StringTerm(string(v)).SetLocation(term.Location)
81		path = append(path, s)
82	}
83	pkg := &Package{Location: loc, Path: path}
84	return pkg, nil
85}
86
87func makeImport(loc *Location, path, alias interface{}) (interface{}, error) {
88	imp := &Import{}
89	imp.Location = loc
90	imp.Path = path.(*Term)
91	if err := IsValidImportPath(imp.Path.Value); err != nil {
92		return nil, err
93	}
94	if alias == nil {
95		return imp, nil
96	}
97	aliasSlice := alias.([]interface{})
98	// Import definition above describes the "alias" slice. We only care about the "Var" element.
99	imp.Alias = aliasSlice[3].(*Term).Value.(Var)
100	return imp, nil
101}
102
103func makeDefaultRule(loc *Location, name, value interface{}) (interface{}, error) {
104
105	term := value.(*Term)
106	var err error
107
108	vis := NewGenericVisitor(func(x interface{}) bool {
109		if err != nil {
110			return true
111		}
112		switch x.(type) {
113		case *ArrayComprehension, *ObjectComprehension, *SetComprehension: // skip closures
114			return true
115		case Ref, Var:
116			err = fmt.Errorf("default rule value cannot contain %v", TypeName(x))
117			return true
118		}
119		return false
120	})
121
122	Walk(vis, term)
123
124	if err != nil {
125		return nil, err
126	}
127
128	body := NewBody(NewExpr(BooleanTerm(true).SetLocation(loc)))
129
130	rule := &Rule{
131		Location: loc,
132		Default:  true,
133		Head: &Head{
134			Location: loc,
135			Name:     name.(*Term).Value.(Var),
136			Value:    value.(*Term),
137		},
138		Body: body,
139	}
140	rule.Body[0].Location = loc
141
142	return []*Rule{rule}, nil
143}
144
145func makeRule(loc *Location, head, rest interface{}) (interface{}, error) {
146
147	if head == nil {
148		return nil, nil
149	}
150
151	sl := rest.([]interface{})
152
153	rules := []*Rule{
154		{
155			Location: loc,
156			Head:     head.(*Head),
157			Body:     sl[0].(Body),
158		},
159	}
160
161	var ordered bool
162	prev := rules[0]
163
164	for i, elem := range sl[1].([]interface{}) {
165
166		next := elem.([]interface{})
167		re := next[1].(ruleExt)
168
169		if re.term == nil {
170			if ordered {
171				return nil, fmt.Errorf("expected 'else' keyword")
172			}
173			rules = append(rules, &Rule{
174				Location: re.loc,
175				Head:     prev.Head.Copy(),
176				Body:     re.body,
177			})
178		} else {
179			if (rules[0].Head.DocKind() != CompleteDoc) || (i != 0 && !ordered) {
180				return nil, fmt.Errorf("unexpected 'else' keyword")
181			}
182			ordered = true
183			curr := &Rule{
184				Location: re.loc,
185				Head: &Head{
186					Name:     prev.Head.Name,
187					Args:     prev.Head.Args.Copy(),
188					Value:    re.term,
189					Location: re.term.Location,
190				},
191				Body: re.body,
192			}
193			prev.Else = curr
194			prev = curr
195		}
196	}
197
198	return rules, nil
199}
200
201func makeRuleHead(loc *Location, name, args, key, value interface{}) (interface{}, error) {
202
203	head := &Head{}
204
205	head.Location = loc
206	head.Name = name.(*Term).Value.(Var)
207
208	if args != nil && key != nil {
209		return nil, fmt.Errorf("partial rules cannot take arguments")
210	}
211
212	if args != nil {
213		argSlice := args.([]interface{})
214		head.Args = argSlice[3].(Args)
215	}
216
217	if key != nil {
218		keySlice := key.([]interface{})
219		// Head definition above describes the "key" slice. We care about the "Term" element.
220		head.Key = keySlice[3].(*Term)
221	}
222
223	if value != nil {
224		valueSlice := value.([]interface{})
225		// Head definition above describes the "value" slice. We care about the "Term" element.
226		head.Value = valueSlice[len(valueSlice)-1].(*Term)
227	}
228
229	if key == nil && value == nil {
230		head.Value = BooleanTerm(true).SetLocation(head.Location)
231	}
232
233	if key != nil && value != nil {
234		switch head.Key.Value.(type) {
235		case Var, String, Ref: // nop
236		default:
237			return nil, fmt.Errorf("object key must be string, var, or ref, not %v", TypeName(head.Key.Value))
238		}
239	}
240
241	return head, nil
242}
243
244func makeArgs(list interface{}) (interface{}, error) {
245	termSlice := list.([]*Term)
246	args := make(Args, len(termSlice))
247	for i := 0; i < len(args); i++ {
248		args[i] = termSlice[i]
249	}
250	return args, nil
251}
252
253func makeRuleExt(loc *Location, val, b interface{}) (interface{}, error) {
254	bs := b.([]interface{})
255	body := bs[1].(Body)
256
257	if val == nil {
258		term := BooleanTerm(true)
259		term.Location = loc
260		return ruleExt{term.Location, term, body}, nil
261	}
262
263	vs := val.([]interface{})
264	t := vs[3].(*Term)
265	return ruleExt{loc, t, body}, nil
266}
267
268func makeLiteral(negated, value, with interface{}) (interface{}, error) {
269
270	expr := value.(*Expr)
271
272	expr.Negated = negated.(bool)
273
274	if with != nil {
275		expr.With = with.([]*With)
276	}
277
278	return expr, nil
279}
280
281func makeLiteralExpr(loc *Location, lhs, rest interface{}) (interface{}, error) {
282
283	if rest == nil {
284		if call, ok := lhs.(*Term).Value.(Call); ok {
285			return NewExpr([]*Term(call)).SetLocation(loc), nil
286		}
287		return NewExpr(lhs).SetLocation(loc), nil
288	}
289
290	termSlice := rest.([]interface{})
291	terms := []*Term{
292		termSlice[1].(*Term),
293		lhs.(*Term),
294		termSlice[3].(*Term),
295	}
296
297	expr := NewExpr(terms).SetLocation(loc)
298
299	return expr, nil
300}
301
302func makeWithKeywordList(head, tail interface{}) (interface{}, error) {
303	var withs []*With
304
305	if head == nil {
306		return withs, nil
307	}
308
309	sl := tail.([]interface{})
310
311	withs = make([]*With, 0, len(sl)+1)
312	withs = append(withs, head.(*With))
313
314	for i := range sl {
315		withSlice := sl[i].([]interface{})
316		withs = append(withs, withSlice[1].(*With))
317	}
318
319	return withs, nil
320}
321
322func makeWithKeyword(loc *Location, target, value interface{}) (interface{}, error) {
323	w := &With{
324		Target: target.(*Term),
325		Value:  value.(*Term),
326	}
327	return w.SetLocation(loc), nil
328}
329
330func makeExprTerm(loc *Location, lhs, rest interface{}) (interface{}, error) {
331
332	if rest == nil {
333		return lhs, nil
334	}
335
336	sl := rest.([]interface{})
337
338	if len(sl) == 0 {
339		return lhs, nil
340	}
341
342	for i := range sl {
343		termSlice := sl[i].([]interface{})
344		call := Call{
345			termSlice[1].(*Term),
346			lhs.(*Term),
347			termSlice[3].(*Term),
348		}
349		lhs = NewTerm(call).SetLocation(loc)
350	}
351
352	return lhs, nil
353}
354
355func makeCall(loc *Location, operator, args interface{}) (interface{}, error) {
356
357	termSlice := args.([]*Term)
358	termOperator := operator.(*Term)
359
360	call := make(Call, len(termSlice)+1)
361
362	if _, ok := termOperator.Value.(Var); ok {
363		termOperator = RefTerm(termOperator).SetLocation(loc)
364	}
365
366	call[0] = termOperator
367
368	for i := 1; i < len(call); i++ {
369		call[i] = termSlice[i-1]
370	}
371
372	return NewTerm(call).SetLocation(loc), nil
373}
374
375func makeBraceEnclosedBody(loc *Location, body interface{}) (interface{}, error) {
376	if body != nil {
377		return body, nil
378	}
379	return NewBody(NewExpr(ObjectTerm().SetLocation(loc)).SetLocation(loc)), nil
380}
381
382func makeBody(head, tail interface{}, pos int) (interface{}, error) {
383
384	sl := tail.([]interface{})
385	body := make(Body, len(sl)+1)
386	body[0] = head.(*Expr)
387
388	for i := 1; i < len(body); i++ {
389		body[i] = sl[i-1].([]interface{})[pos].(*Expr)
390	}
391
392	return body, nil
393}
394
395func makeExprTermList(head, tail interface{}) (interface{}, error) {
396
397	var terms []*Term
398
399	if head == nil {
400		return terms, nil
401	}
402
403	sl := tail.([]interface{})
404
405	terms = make([]*Term, 0, len(sl)+1)
406	terms = append(terms, head.(*Term))
407
408	for i := range sl {
409		termSlice := sl[i].([]interface{})
410		terms = append(terms, termSlice[3].(*Term))
411	}
412
413	return terms, nil
414}
415
416func makeExprTermPairList(head, tail interface{}) (interface{}, error) {
417
418	var terms [][2]*Term
419
420	if head == nil {
421		return terms, nil
422	}
423
424	sl := tail.([]interface{})
425
426	terms = make([][2]*Term, 0, len(sl)+1)
427	terms = append(terms, head.([2]*Term))
428
429	for i := range sl {
430		termSlice := sl[i].([]interface{})
431		terms = append(terms, termSlice[3].([2]*Term))
432	}
433
434	return terms, nil
435}
436
437func makeExprTermPair(key, value interface{}) (interface{}, error) {
438	return [2]*Term{key.(*Term), value.(*Term)}, nil
439}
440
441func makeInfixOperator(loc *Location, text []byte) (interface{}, error) {
442	op := string(text)
443	for _, b := range Builtins {
444		if string(b.Infix) == op {
445			op = string(b.Name)
446		}
447	}
448	operator := RefTerm(VarTerm(op).SetLocation(loc)).SetLocation(loc)
449	return operator, nil
450}
451
452func makeArray(loc *Location, list interface{}) (interface{}, error) {
453	termSlice := list.([]*Term)
454	return ArrayTerm(termSlice...).SetLocation(loc), nil
455}
456
457func makeObject(loc *Location, list interface{}) (interface{}, error) {
458	termPairSlice := list.([][2]*Term)
459	return ObjectTerm(termPairSlice...).SetLocation(loc), nil
460}
461
462func makeSet(loc *Location, list interface{}) (interface{}, error) {
463	termSlice := list.([]*Term)
464	return SetTerm(termSlice...).SetLocation(loc), nil
465}
466
467func makeArrayComprehension(loc *Location, head, body interface{}) (interface{}, error) {
468	return ArrayComprehensionTerm(head.(*Term), body.(Body)).SetLocation(loc), nil
469}
470
471func makeSetComprehension(loc *Location, head, body interface{}) (interface{}, error) {
472	return SetComprehensionTerm(head.(*Term), body.(Body)).SetLocation(loc), nil
473}
474
475func makeObjectComprehension(loc *Location, head, body interface{}) (interface{}, error) {
476	pair := head.([2]*Term)
477	return ObjectComprehensionTerm(pair[0], pair[1], body.(Body)).SetLocation(loc), nil
478}
479
480func makeRef(loc *Location, head, rest interface{}) (interface{}, error) {
481
482	headTerm := head.(*Term)
483	ifaceSlice := rest.([]interface{})
484
485	ref := make(Ref, len(ifaceSlice)+1)
486	ref[0] = headTerm
487
488	for i := 1; i < len(ref); i++ {
489		ref[i] = ifaceSlice[i-1].(*Term)
490	}
491
492	return NewTerm(ref).SetLocation(loc), nil
493}
494
495func makeRefOperandDot(loc *Location, val interface{}) (interface{}, error) {
496	return StringTerm(string(val.(*Term).Value.(Var))).SetLocation(loc), nil
497}
498
499func makeVar(loc *Location, text interface{}) (interface{}, error) {
500	str := string(text.([]byte))
501	return VarTerm(str).SetLocation(loc), nil
502}
503
504func makeNumber(loc *Location, text interface{}) (interface{}, error) {
505	f, ok := new(big.Float).SetString(string(text.([]byte)))
506	if !ok {
507		// This indicates the grammar is out-of-sync with what the string
508		// representation of floating point numbers. This should not be
509		// possible.
510		panic("illegal value")
511	}
512	return NumberTerm(json.Number(f.String())).SetLocation(loc), nil
513}
514
515func makeString(loc *Location, text interface{}) (interface{}, error) {
516	var v string
517	err := json.Unmarshal(text.([]byte), &v)
518	return StringTerm(v).SetLocation(loc), err
519}
520
521func makeRawString(loc *Location, text interface{}) (interface{}, error) {
522	s := string(text.([]byte))
523	s = s[1 : len(s)-1] // Trim surrounding quotes.
524	return StringTerm(s).SetLocation(loc), nil
525}
526
527func makeBool(loc *Location, text interface{}) (interface{}, error) {
528	var term *Term
529	if string(text.([]byte)) == "true" {
530		term = BooleanTerm(true)
531	} else {
532		term = BooleanTerm(false)
533	}
534	return term.SetLocation(loc), nil
535}
536
537func makeNull(loc *Location) (interface{}, error) {
538	return NullTerm().SetLocation(loc), nil
539}
540
541func makeComments(c *current, text interface{}) (interface{}, error) {
542
543	var buf bytes.Buffer
544	for _, x := range text.([]interface{}) {
545		buf.Write(x.([]byte))
546	}
547
548	comment := NewComment(buf.Bytes())
549	comment.Location = currentLocation(c)
550	comments := c.globalStore[commentsKey].([]*Comment)
551	comments = append(comments, comment)
552	c.globalStore[commentsKey] = comments
553
554	return comment, nil
555}
556
557func ifacesToBody(i interface{}, a ...interface{}) Body {
558	var buf Body
559	buf = append(buf, i.(*Expr))
560	for _, s := range a {
561		expr := s.([]interface{})[3].(*Expr)
562		buf = append(buf, expr)
563	}
564	return buf
565}
566