compiler/compiler.go
func (c *BasicCompiler) Compile(ast *parser.AST) (*vm.ByteCode, error) {
	ctx := &context{
		ByteCode: vm.NewByteCode(),
	}
	for _, n := range ast.Root.Nodes {
		compile(ctx, n)
	}

	// When we're done compiling, always append an END op
	ctx.ByteCode.AppendOp(vm.TXOPEnd)

	opt := &NaiveOptimizer{}
	opt.Optimize(ctx.ByteCode)

	ctx.ByteCode.Name = ast.Name
	return ctx.ByteCode, nil
}
func (c *BasicCompiler) Compile(ast *parser.AST) (*vm.ByteCode, error) {
	ctx := &context{
		ByteCode: vm.NewByteCode(),
	}
	for _, n := range ast.Root.Nodes {
		compile(ctx, n)
	}

	// When we're done compiling, always append an END op
	ctx.ByteCode.AppendOp(vm.TXOPEnd)

	opt := &NaiveOptimizer{}
	opt.Optimize(ctx.ByteCode)

	ctx.ByteCode.Name = ast.Name
	return ctx.ByteCode, nil
}
// Compile satisfies the compiler.Compiler interface. It accepts an AST
// created by parser.Parser, and returns vm.ByteCode or an error