1/*
2 * gomacro - A Go interpreter with Lisp-like macros
3 *
4 * Copyright (C) 2017-2019 Massimiliano Ghilardi
5 *
6 *     This Source Code Form is subject to the terms of the Mozilla Public
7 *     License, v. 2.0. If a copy of the MPL was not distributed with this
8 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 *
11 * expr1.go
12 *
13 *  Created on Apr 03, 2017
14 *      Author Massimiliano Ghilardi
15 */
16
17package fast
18
19import (
20	"go/constant"
21	r "reflect"
22
23	"github.com/cosmos72/gomacro/base/output"
24	"github.com/cosmos72/gomacro/base/reflect"
25	"github.com/cosmos72/gomacro/base/untyped"
26	xr "github.com/cosmos72/gomacro/xreflect"
27)
28
29func (c *Comp) litValue(value I) Lit {
30	return Lit{Type: c.TypeOf(value), Value: value}
31}
32
33func (c *Comp) exprUntypedLit(kind untyped.Kind, obj constant.Value) *Expr {
34	return &Expr{Lit: Lit{Type: c.TypeOfUntypedLit(), Value: untyped.MakeLit(kind, obj, &c.Universe.BasicTypes)}}
35}
36
37func (c *Comp) exprValue(t xr.Type, value I) *Expr {
38	if t == nil {
39		t = c.TypeOf(value)
40	}
41	return exprValue(t, value)
42}
43
44func exprValue(t xr.Type, value I) *Expr {
45	if t == nil {
46		output.Errorf("internal error! exprValue() value = %v invoked with type = nil", value)
47	}
48	return &Expr{
49		Lit:    Lit{Type: t, Value: value},
50		EFlags: EFlag4Value(value),
51	}
52}
53
54func exprLit(lit Lit, sym *Symbol) *Expr {
55	return &Expr{Lit: lit, Sym: sym, EFlags: EFlag4Value(lit.Value)}
56}
57
58func exprFun(t xr.Type, fun I) *Expr {
59	return &Expr{Lit: Lit{Type: t}, Fun: fun}
60}
61
62func exprX1(t xr.Type, fun func(env *Env) r.Value) *Expr {
63	return &Expr{Lit: Lit{Type: t}, Fun: fun}
64}
65
66func exprXV(types []xr.Type, fun func(env *Env) (r.Value, []r.Value)) *Expr {
67	if len(types) == 1 {
68		return &Expr{Lit: Lit{Type: types[0]}, Fun: fun}
69	} else {
70		return &Expr{Lit: Lit{Type: types[0]}, Types: types, Fun: fun}
71	}
72}
73
74func expr0(fun func(env *Env)) *Expr {
75	return &Expr{Types: zeroTypes, Fun: fun}
76}
77
78func (c *Comp) exprBool(fun func(env *Env) bool) *Expr {
79	return &Expr{Lit: Lit{Type: c.TypeOfBool()}, Fun: fun}
80}
81
82func (c *Comp) exprUint8(fun func(env *Env) uint8) *Expr {
83	return &Expr{Lit: Lit{Type: c.TypeOfUint8()}, Fun: fun}
84}
85
86func (c *Comp) exprString(fun func(env *Env) string) *Expr {
87	return &Expr{Lit: Lit{Type: c.TypeOfString()}, Fun: fun}
88}
89
90func (expr *Expr) EvalConst(opts CompileOptions) I {
91	if expr == nil {
92		return nil
93	}
94	if expr.Const() {
95		if opts == COptDefaults && expr.Untyped() {
96			return expr.ConstTo(expr.DefaultType())
97		}
98		return expr.Value
99	}
100	ret := expr.AsX1()(nil)
101	if ret == reflect.None {
102		output.Errorf("constant should evaluate to a single value, found no values at all")
103		return nil
104	}
105	var value I
106	if ret != reflect.Nil {
107		value = ret.Interface()
108	}
109	expr.Value = value
110	expr.EFlags = EFlag4Value(value)
111	expr.Fun = nil // no longer needed, will be recreated if needed as a wrapper for the computed value
112	return value
113}
114