Example #1
0
// noOp is the dual of noVar. It also checks for assignment to builtins.
// It just errors out if there is a conflict.
func (c *Context) noOp(name string) {
	if name == "pi" || name == "e" { // Cannot redefine these.
		value.Errorf("cannot reassign %q", name)
	}
	if c.UnaryFn[name] == nil && c.BinaryFn[name] == nil {
		return
	}
	value.Errorf("cannot define variable %s; it is an op", name)
}
Example #2
0
// noVar guarantees that there is no global variable with that name,
// preventing an op from being defined with the same name as a variable,
// which could cause problems. A variable with value zero is considered to
// be OK, so one can clear a variable before defining a symbol. A cleared
// variable is removed from the global symbol table.
// noVar also prevents defining builtin variables as ops.
func (c *Context) noVar(name string) {
	if name == "_" || name == "pi" || name == "e" { // Cannot redefine these.
		value.Errorf(`cannot define op with name %q`, name)
	}
	sym := c.Stack[0][name]
	if sym == nil {
		return
	}
	if i, ok := sym.(value.Int); ok && i == 0 {
		delete(c.Stack[0], name)
		return
	}
	value.Errorf("cannot define op %s; it is a variable (%[1]s=0 to clear)", name)
}
Example #3
0
File: parse.go Project: db47h/ivy
func (e variableExpr) Eval(context value.Context) value.Value {
	v := context.Lookup(e.name)
	if v == nil {
		value.Errorf("undefined variable %q", e.name)
	}
	return v
}
Example #4
0
func (u *unaryCall) Eval(context value.Context) value.Value {
	arg := u.arg.Eval(context)
	context.Push()
	defer context.Pop()
	exec := context.(*execContext) // Sigh.
	fn := exec.unaryFn[u.name]
	if fn == nil || fn.body == nil {
		value.Errorf("unary %q undefined", u.name)
	}
	context.AssignLocal(fn.right.name, arg)
	var v value.Value
	for _, e := range fn.body {
		v = e.Eval(context)
	}
	if v == nil {
		value.Errorf("no value returned by %q", u.name)
	}
	return v
}
Example #5
0
// EvalUnary evaluates a unary operator.
func (c *Context) EvalUnary(op string, right value.Value) value.Value {
	right = right.Eval(c)
	fn := c.UnaryFn[op]
	if fn == nil {
		return value.Unary(c, op, right)
	}
	if fn.Body == nil {
		value.Errorf("unary %q undefined", op)
	}
	c.push()
	defer c.pop()
	c.assignLocal(fn.Right, right)
	var v value.Value
	for _, e := range fn.Body {
		v = e.Eval(c)
	}
	if v == nil {
		value.Errorf("no value returned by %q", op)
	}
	return v
}
Example #6
0
File: parse.go Project: db47h/ivy
func (s sliceExpr) Eval(context value.Context) value.Value {
	v := make([]value.Value, len(s))
	for i, x := range s {
		elem := x.Eval(context)
		// Each element must be a singleton.
		if !isScalar(elem) {
			value.Errorf("vector element must be scalar; have %s", elem)
		}
		v[i] = elem
	}
	return value.NewVector(v)
}
Example #7
0
func (b *binaryCall) Eval(context value.Context) value.Value {
	left := b.left.Eval(context)
	right := b.right.Eval(context)
	context.Push()
	defer context.Pop()
	exec := context.(*execContext) // Sigh.
	fn := exec.binaryFn[b.name]
	if fn == nil || fn.body == nil {
		value.Errorf("binary %q undefined", b.name)
	}
	context.AssignLocal(fn.left.name, left)
	context.AssignLocal(fn.right.name, right)
	var v value.Value
	for _, e := range fn.body {
		v = e.Eval(context)
	}
	if v == nil {
		value.Errorf("no value returned by %q", b.name)
	}
	return v
}
Example #8
0
// Assign assigns the variable the value. The variable must
// be defined either in the current function or globally.
// Inside a function, new variables become locals.
func (c *Context) Assign(name string, val value.Value) {
	n := len(c.Stack)
	if n == 0 {
		value.Errorf("empty stack; cannot happen")
	}
	globals := c.Stack[0]
	if n > 1 {
		// In this function?
		frame := c.Stack[n-1]
		_, globallyDefined := globals[name]
		if _, ok := frame[name]; ok || !globallyDefined {
			frame[name] = val
			return
		}
	}
	// Assign global variable.
	c.noOp(name)
	globals[name] = val
}
Example #9
0
File: save.go Project: zzn01/ivy
// put writes to out a version of the value that will recreate it when parsed.
func put(out io.Writer, val value.Value) {
	switch val := val.(type) {
	case value.Char:
		fmt.Fprintf(out, "%q", rune(val))
	case value.Int:
		fmt.Fprintf(out, "%d", int(val))
	case value.BigInt:
		fmt.Fprintf(out, "%d", val.Int)
	case value.BigRat:
		fmt.Fprintf(out, "%d/%d", val.Num(), val.Denom())
	case value.BigFloat:
		// TODO The actual value might not have the same prec as
		// the configuration, so we might not get this right
		// Probably not important but it would be nice to fix it.
		if val.Sign() == 0 || val.IsInf() {
			// These have prec 0 and are easy.
			// They shouldn't appear anyway, but be safe.
			fmt.Fprintf(out, "%g", val)
			return
		}
		digits := int(float64(val.Prec()) * 0.301029995664) // 10 log 2.
		fmt.Fprintf(out, "%.*g", digits, val.Float)
	case value.Vector:
		if val.AllChars() {
			fmt.Fprintf(out, "%q", val)
			return
		}
		for i, v := range val {
			if i > 0 {
				fmt.Fprint(out, " ")
			}
			put(out, v)
		}
	case value.Matrix:
		put(out, val.Shape())
		fmt.Fprint(out, " rho ")
		put(out, val.Data())
	default:
		value.Errorf("internal error: can't save type %T", val)
	}
}
Example #10
0
File: save.go Project: zzn01/ivy
// save writes the state of the workspace to the named file.
// The format of the output is ivy source text.
func save(c *exec.Context, file string, conf *config.Config) {
	// "<conf.out>" is a special case for testing.
	out := conf.Output()
	if file != "<conf.out>" {
		fd, err := os.Create(file)
		if err != nil {
			value.Errorf("%s", err)
		}
		defer fd.Close()
		buf := bufio.NewWriter(fd)
		defer buf.Flush()
		out = buf
	}

	// Configuration settings. We will set the base below,
	// after we have printed all numbers in base 10.
	fmt.Fprintf(out, ")prec %d\n", conf.FloatPrec())
	ibase, obase := conf.Base()
	fmt.Fprintf(out, ")maxbits %d\n", conf.MaxBits())
	fmt.Fprintf(out, ")maxdigits %d\n", conf.MaxDigits())
	fmt.Fprintf(out, ")origin %d\n", conf.Origin())
	fmt.Fprintf(out, ")prompt %q\n", conf.Prompt())
	fmt.Fprintf(out, ")format %q\n", conf.Format())

	// Ops.
	printed := make(map[exec.OpDef]bool)
	for _, def := range c.Defs {
		var fn *exec.Function
		if def.IsBinary {
			fn = c.BinaryFn[def.Name]
		} else {
			fn = c.UnaryFn[def.Name]
		}
		for _, ref := range references(c, fn.Body) {
			if !printed[ref] {
				if ref.IsBinary {
					fmt.Fprintf(out, "op _ %s _\n", ref.Name)
				} else {
					fmt.Fprintf(out, "op %s _\n", ref.Name)
				}
				printed[ref] = true
			}
		}
		printed[def] = true
		fmt.Fprintln(out, fn)
	}

	// Global variables.
	syms := c.Stack[0]
	if len(syms) > 0 {
		// Set the base strictly to 10 for output.
		fmt.Fprintf(out, "# Set base 10 for parsing numbers.\n)base 10\n")
		// Sort the names for consistent output.
		sorted := sortSyms(syms)
		for _, sym := range sorted {
			// pi and e are generated
			if sym.name == "pi" || sym.name == "e" {
				continue
			}
			fmt.Fprintf(out, "%s = ", sym.name)
			put(out, sym.val)
			fmt.Fprint(out, "\n")
		}
	}

	// Now we can set the base.
	fmt.Fprintf(out, ")ibase %d\n", ibase)
	fmt.Fprintf(out, ")obase %d\n", obase)
}
Example #11
0
File: parse.go Project: db47h/ivy
func (p *Parser) errorf(format string, args ...interface{}) {
	p.peekTok = scan.Token{Type: scan.EOF}
	value.Errorf(format, args...)
}