eval.go raw

   1  package wasm
   2  
   3  import (
   4  	"bytes"
   5  	"fmt"
   6  	"io"
   7  )
   8  
   9  const (
  10  	opEnd      = 0x0B // end
  11  	opI32Const = 0x41 // i32.const
  12  	opI64Const = 0x42 // i64.const
  13  )
  14  
  15  // Eval tries to evaluate the (constant) expression in the buffer. It returns
  16  // the evaluation stack at the end of the sequence or an error, if there was
  17  // one.
  18  func Eval(r *bytes.Buffer) ([]interface{}, error) {
  19  	// Right now, this is only meant to parse very simple expressions like the
  20  	// one used for the start offset of a data segment (which is an expression).
  21  	var stack []interface{}
  22  	for {
  23  		b, err := r.ReadByte()
  24  		if err == io.EOF {
  25  			return nil, io.ErrUnexpectedEOF
  26  		}
  27  		if b == opEnd {
  28  			// End of expression.
  29  			break
  30  		}
  31  		switch b {
  32  		case opI32Const:
  33  			var n int32
  34  			err := readVarInt32(r, &n)
  35  			if err != nil {
  36  				return nil, err
  37  			}
  38  			stack = append(stack, n)
  39  		default:
  40  			return nil, fmt.Errorf("unknown opcode: 0x%02X", b)
  41  		}
  42  	}
  43  	return stack, nil
  44  }
  45  
  46  // Read a sequence of instructions used to initialize something.
  47  func readInitExpr(r io.Reader, expr *[]byte) error {
  48  	for {
  49  		// Read a single byte.
  50  		b, err := readByte(r)
  51  		if err != nil {
  52  			return err
  53  		}
  54  		*expr = append(*expr, b)
  55  		switch b {
  56  		case opEnd:
  57  			return nil // finished the expression
  58  		case opI32Const, opI64Const:
  59  			// Read a single LEB128 encoded number.
  60  			for {
  61  				b, err := readByte(r)
  62  				if err != nil {
  63  					return err
  64  				}
  65  				*expr = append(*expr, b)
  66  				if (b & 0x80) == 0 {
  67  					break
  68  				}
  69  			}
  70  		default:
  71  			return fmt.Errorf("unknown opcode in init expression: 0x%02X", b)
  72  		}
  73  	}
  74  }
  75