aboutsummaryrefslogblamecommitdiffstats
path: root/ethutil/parsing.go
blob: 9775cf328e978a46726e1c072cb3ad0f4b058aaa (plain) (tree)
1
2
3
4
5
6
7
8
9


               
               
                  
                  


           
                              

























                                     







                             


                                        




                           

                                               



                       










                        
                        




                                



                             

 




                                     
         

                    
 













                                                          



                                                 
                 
 

                                       

                                                                  

                                                    
         
 
                       

 

                                   

                                                            
 
                                          

                                             

                                                 



              









                                                     


















                                                            













































                                                                                           
package ethutil

import (
    _ "fmt"
    "math/big"
    _ "regexp"
)

// Op codes
var OpCodes = map[string]byte{
    // 0x0 range - arithmetic ops
    "STOP": 0x00,
    "ADD":  0x01,
    "MUL":  0x02,
    "SUB":  0x03,
    "DIV":  0x04,
    "SDIV": 0x05,
    "MOD":  0x06,
    "SMOD": 0x07,
    "EXP":  0x08,
    "NEG":  0x09,
    "LT":   0x0a,
    "GT":   0x0b,
    "EQ":   0x0c,
    "NOT":  0x0d,

    // 0x10 range - bit ops
    "AND":  0x10,
    "OR":   0x11,
    "XOR":  0x12,
    "BYTE": 0x13,

    // 0x20 range - crypto
    "SHA3": 0x20,

    // 0x30 range - closure state
    "ADDRESS":      0x30,
    "BALANCE":      0x31,
    "ORIGIN":       0x32,
    "CALLER":       0x33,
    "CALLVALUE":    0x34,
    "CALLDATA":     0x35,
    "CALLDATASIZE": 0x36,
    "GASPRICE":     0x38,

    // 0x40 range - block operations
    "PREVHASH":   0x40,
    "COINBASE":   0x41,
    "TIMESTAMP":  0x42,
    "NUMBER":     0x43,
    "DIFFICULTY": 0x44,
    "GASLIMIT":   0x45,

    // 0x50 range - 'storage' and execution
    "PUSH": 0x50,

    "PUSH20": 0x80,

    "POP":     0x51,
    "DUP":     0x52,
    "SWAP":    0x53,
    "MLOAD":   0x54,
    "MSTORE":  0x55,
    "MSTORE8": 0x56,
    "SLOAD":   0x57,
    "SSTORE":  0x58,
    "JUMP":    0x59,
    "JUMPI":   0x5a,
    "PC":      0x5b,
    "MSIZE":   0x5c,

    // 0x60 range - closures
    "CREATE": 0x60,
    "CALL":   0x61,
    "RETURN": 0x62,

    // 0x70 range - other
    "LOG":     0x70,
    "SUICIDE": 0x7f,
}

func IsOpCode(s string) bool {
    for key, _ := range OpCodes {
        if key == s {
            return true
        }
    }
    return false
}

func CompileInstr(s interface{}) ([]byte, error) {
    switch s.(type) {
    case string:
        str := s.(string)
        isOp := IsOpCode(str)
        if isOp {
            return []byte{OpCodes[str]}, nil
        }

        num := new(big.Int)
        _, success := num.SetString(str, 0)
        // Assume regular bytes during compilation
        if !success {
            num.SetBytes([]byte(str))
        } else {
            // tmp fix for 32 bytes
            n := BigToBytes(num, 256)
            return n, nil
        }

        return num.Bytes(), nil
    case int:
        num := BigToBytes(big.NewInt(int64(s.(int))), 256)
        return num, nil
    case []byte:
        return BigD(s.([]byte)).Bytes(), nil
    }

    return nil, nil
}

// Script compilation functions
// Compiles strings to machine code
func Assemble(instructions ...interface{}) (script []byte) {
    //script = make([]string, len(instructions))

    for _, val := range instructions {
        instr, _ := CompileInstr(val)

        //script[i] = string(instr)
        script = append(script, instr...)
    }

    return
}

/*
Prepocessing function that takes init and main apart:
init() {
    // something
}

main() {
    // main something
}
func PreProcess(data string) (mainInput, initInput string) {
    reg := "\\(\\)\\s*{([\\d\\w\\W\\n\\s]+?)}"
    mainReg := regexp.MustCompile("main" + reg)
    initReg := regexp.MustCompile("init" + reg)

    main := mainReg.FindStringSubmatch(data)
    if len(main) > 0 {
        mainInput = main[1]
    } else {
        mainInput = data
    }

    init := initReg.FindStringSubmatch(data)
    if len(init) > 0 {
        initInput = init[1]
    }

    return
}
*/

// Very, very dumb parser. Heed no attention :-)
func FindFor(blockMatcher, input string) string {
    curCount := -1
    length := len(blockMatcher)
    matchfst := rune(blockMatcher[0])
    var currStr string

    for i, run := range input {
        // Find init
        if curCount == -1 && run == matchfst && input[i:i+length] == blockMatcher {
            curCount = 0
        } else if curCount > -1 {
            if run == '{' {
                curCount++
                if curCount == 1 {
                    continue
                }
            } else if run == '}' {
                curCount--
                if curCount == 0 {
                    // we are done
                    curCount = -1
                    break
                }
            }

            if curCount > 0 {
                currStr += string(run)
            }
        }
    }

    return currStr
}

func PreProcess(data string) (mainInput, initInput string) {
    mainInput = FindFor("main", data)
    if mainInput == "" {
        mainInput = data
    }
    initInput = FindFor("init", data)

    return
}