Merge branch 'develop' into bzz

This commit is contained in:
Daniel A. Nagy 2015-03-24 13:47:57 +01:00
commit d8dfe4112d
972 changed files with 63674 additions and 30058 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "ethereal/assets/samplecoin"]
path = ethereal/assets/samplecoin
url = git@github.com:obscuren/SampleCoin.git
[submodule "cmd/mist/assets/ext/ethereum.js"]
path = cmd/mist/assets/ext/ethereum.js
url = https://github.com/ethereum/ethereum.js

View file

@ -27,3 +27,10 @@ env:
- LD_LIBRARY_PATH=/opt/qt54/lib
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/e09ccdce1048c5e03445
on_success: change # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false

View file

@ -26,12 +26,11 @@ RUN tar -C /usr/local -xzf go*.tar.gz && go version
ADD https://api.github.com/repos/ethereum/go-ethereum/git/refs/heads/develop file_does_not_exist
## Fetch and install go-ethereum
RUN go get github.com/tools/godep
RUN go get -d github.com/ethereum/go-ethereum/...
RUN mkdir -p $GOPATH/src/github.com/ethereum/
RUN git clone https://github.com/ethereum/go-ethereum $GOPATH/src/github.com/ethereum/go-ethereum
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
RUN git checkout develop
RUN godep restore
RUN go install -v ./cmd/ethereum
RUN GOPATH=$GOPATH:$GOPATH/src/github.com/ethereum/go-ethereum/Godeps/_workspace go install -v ./cmd/ethereum
## Run & expose JSON RPC
ENTRYPOINT ["ethereum", "-rpc=true", "-rpcport=8545"]

8
Godeps/Godeps.json generated
View file

@ -22,8 +22,8 @@
},
{
"ImportPath": "github.com/ethereum/ethash",
"Comment": "v17-64-ga323708",
"Rev": "a323708b8c4d253b8567bf6c72727d1aec302225"
"Comment": "v23.1-26-g934bb4f",
"Rev": "934bb4f5060ab69d96fb6eba4b9a57facc4e160b"
},
{
"ImportPath": "github.com/ethereum/serpent-go",
@ -47,8 +47,8 @@
"Rev": "ccfcd0245381f0c94c68f50626665eed3c6b726a"
},
{
"ImportPath": "github.com/obscuren/otto",
"Rev": "cf13cc4228c5e5ce0fe27a7aea90bc10091c4f19"
"ImportPath": "github.com/robertkrimen/otto",
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
},
{
"ImportPath": "github.com/obscuren/qml",

View file

@ -8,3 +8,5 @@ pyethash.egg-info/
*.so
*~
*.swp
MANIFEST
dist/

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.8.7)
project(ethash)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
set(ETHHASH_LIBS ethash)
if (WIN32 AND WANT_CRYPTOPP)
@ -10,6 +10,12 @@ endif()
add_subdirectory(src/libethash)
# bin2h.cmake doesn't work
#add_subdirectory(src/libethash-cl EXCLUDE_FROM_ALL)
if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
add_subdirectory(src/libethash-cl)
endif()
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
add_subdirectory(test/c EXCLUDE_FROM_ALL)

View file

@ -0,0 +1,17 @@
include setup.py
# C sources
include src/libethash/internal.c
include src/libethash/sha3.c
include src/libethash/util.c
include src/python/core.c
# Headers
include src/libethash/compiler.h
include src/libethash/data_sizes.h
include src/libethash/endian.h
include src/libethash/ethash.h
include src/libethash/fnv.h
include src/libethash/internal.h
include src/libethash/sha3.h
include src/libethash/util.h

View file

@ -1,3 +1,6 @@
.PHONY: clean
.PHONY: clean test
test:
./test/test.sh
clean:
rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash/*.{so,pyc}
rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash.so test/python/*.pyc dist/ MANIFEST

View file

@ -8,6 +8,6 @@ file(GLOB SOURCE "../../cryptopp/*.cpp")
add_library(${LIBRARY} ${HEADERS} ${SOURCE})
set(CRYPTOPP_INCLUDE_DIRS "../.." PARENT_SCOPE)
set(CRYPTOPP_INCLUDE_DIRS "../.." "../../../" PARENT_SCOPE)
set(CRYPTOPP_LIBRARIES ${LIBRARY} PARENT_SCOPE)
set(CRYPTOPP_FOUND TRUE PARENT_SCOPE)

View file

@ -1,3 +1,13 @@
/*
###################################################################################
###################################################################################
#################### ####################
#################### EDIT AND YOU SHALL FEEL MY WRATH - jeff ####################
#################### ####################
###################################################################################
###################################################################################
*/
package ethash
/*
@ -11,8 +21,8 @@ import "C"
import (
"bytes"
"encoding/binary"
"fmt"
"io/ioutil"
"log"
"math/big"
"math/rand"
"os"
@ -21,25 +31,26 @@ import (
"time"
"unsafe"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/pow"
)
var tt256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
var minDifficulty = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
var powlogger = logger.NewLogger("POW")
type DAG struct {
SeedBlockNum uint64
dag unsafe.Pointer // full GB of memory for dag
file bool
type ParamsAndCache struct {
params *C.ethash_params
cache *C.ethash_cache
Epoch uint64
}
type ParamsAndCache struct {
params *C.ethash_params
cache *C.ethash_cache
SeedBlockNum uint64
type DAG struct {
dag unsafe.Pointer // full GB of memory for dag
file bool
paramsAndCache *ParamsAndCache
}
type Ethash struct {
@ -48,10 +59,9 @@ type Ethash struct {
chainManager pow.ChainManager
dag *DAG
paramsAndCache *ParamsAndCache
nextdag unsafe.Pointer
ret *C.ethash_return_value
dagMutex *sync.Mutex
cacheMutex *sync.Mutex
dagMutex *sync.RWMutex
cacheMutex *sync.RWMutex
}
func parseNonce(nonce []byte) (uint64, error) {
@ -65,151 +75,214 @@ func parseNonce(nonce []byte) (uint64, error) {
const epochLength uint64 = 30000
func GetSeedBlockNum(blockNum uint64) uint64 {
var seedBlockNum uint64 = 0
if blockNum > epochLength {
seedBlockNum = ((blockNum - 1) / epochLength) * epochLength
func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) (*ParamsAndCache, error) {
if blockNum >= epochLength*2048 {
return nil, fmt.Errorf("block number is out of bounds (value %v, limit is %v)", blockNum, epochLength*2048)
}
return seedBlockNum
}
/*
XXX THIS DOESN'T WORK!! NEEDS FIXING
blockEpoch will underflow and wrap around causing massive issues
func GetSeedBlockNum(blockNum uint64) uint64 {
var seedBlockNum uint64 = 0
if blockNum > epochLength {
seedBlockNum = ((blockNum - 1) / epochLength) * epochLength
}
return seedBlockNum
}
*/
func makeParamsAndCache(chainManager pow.ChainManager, blockNum uint64) *ParamsAndCache {
seedBlockNum := GetSeedBlockNum(blockNum)
paramsAndCache := &ParamsAndCache{
params: new(C.ethash_params),
cache: new(C.ethash_cache),
SeedBlockNum: seedBlockNum,
params: new(C.ethash_params),
cache: new(C.ethash_cache),
Epoch: blockNum / epochLength,
}
C.ethash_params_init(paramsAndCache.params, C.uint32_t(seedBlockNum))
paramsAndCache.cache.mem = C.malloc(paramsAndCache.params.cache_size)
seedHash := chainManager.GetBlockByNumber(seedBlockNum).SeedHash()
C.ethash_params_init(paramsAndCache.params, C.uint32_t(uint32(blockNum)))
paramsAndCache.cache.mem = C.malloc(C.size_t(paramsAndCache.params.cache_size))
log.Println("Making Cache")
seedHash, err := GetSeedHash(blockNum)
if err != nil {
return nil, err
}
powlogger.Infoln("Making Cache")
start := time.Now()
C.ethash_mkcache(paramsAndCache.cache, paramsAndCache.params, (*C.uint8_t)(unsafe.Pointer(&seedHash[0])))
log.Println("Took:", time.Since(start))
powlogger.Infoln("Took:", time.Since(start))
return paramsAndCache
return paramsAndCache, nil
}
func (pow *Ethash) updateCache() {
func (pow *Ethash) UpdateCache(force bool) error {
pow.cacheMutex.Lock()
seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
if pow.paramsAndCache.SeedBlockNum != seedNum {
pow.paramsAndCache = makeParamsAndCache(pow.chainManager, pow.chainManager.CurrentBlock().NumberU64())
defer pow.cacheMutex.Unlock()
thisEpoch := pow.chainManager.CurrentBlock().NumberU64() / epochLength
if force || pow.paramsAndCache.Epoch != thisEpoch {
var err error
pow.paramsAndCache, err = makeParamsAndCache(pow.chainManager, pow.chainManager.CurrentBlock().NumberU64())
if err != nil {
panic(err)
}
}
pow.cacheMutex.Unlock()
return nil
}
func makeDAG(p *ParamsAndCache) *DAG {
d := &DAG{
dag: C.malloc(p.params.full_size),
SeedBlockNum: p.SeedBlockNum,
dag: C.malloc(C.size_t(p.params.full_size)),
file: false,
paramsAndCache: p,
}
donech := make(chan string)
go func() {
t := time.NewTicker(5 * time.Second)
tstart := time.Now()
done:
for {
select {
case <-t.C:
powlogger.Infof("... still generating DAG (%v) ...\n", time.Since(tstart).Seconds())
case str := <-donech:
powlogger.Infof("... %s ...\n", str)
break done
}
}
}()
C.ethash_compute_full_data(d.dag, p.params, p.cache)
donech <- "DAG generation completed"
return d
}
func (pow *Ethash) writeDagToDisk(dag *DAG, seedNum uint64) *os.File {
data := C.GoBytes(unsafe.Pointer(dag.dag), C.int(pow.paramsAndCache.params.full_size))
func (pow *Ethash) writeDagToDisk(dag *DAG, epoch uint64) *os.File {
if epoch > 2048 {
panic(fmt.Errorf("Epoch must be less than 2048 (is %v)", epoch))
}
data := C.GoBytes(unsafe.Pointer(dag.dag), C.int(dag.paramsAndCache.params.full_size))
file, err := os.Create("/tmp/dag")
if err != nil {
panic(err)
}
num := make([]byte, 8)
binary.BigEndian.PutUint64(num, seedNum)
dataEpoch := make([]byte, 8)
binary.BigEndian.PutUint64(dataEpoch, epoch)
file.Write(num)
file.Write(dataEpoch)
file.Write(data)
return file
}
func (pow *Ethash) UpdateDAG() {
pow.cacheMutex.Lock()
pow.dagMutex.Lock()
blockNum := pow.chainManager.CurrentBlock().NumberU64()
if blockNum >= epochLength*2048 {
// This will crash in the 2030s or 2040s
panic(fmt.Errorf("Current block number is out of bounds (value %v, limit is %v)", blockNum, epochLength*2048))
}
seedNum := GetSeedBlockNum(pow.chainManager.CurrentBlock().NumberU64())
if pow.dag == nil || pow.dag.SeedBlockNum != seedNum {
pow.dagMutex.Lock()
defer pow.dagMutex.Unlock()
thisEpoch := blockNum / epochLength
if pow.dag == nil || pow.dag.paramsAndCache.Epoch != thisEpoch {
if pow.dag != nil && pow.dag.dag != nil {
C.free(pow.dag.dag)
pow.dag.dag = nil
}
if pow.dag != nil && pow.dag.paramsAndCache.cache.mem != nil {
C.free(pow.dag.paramsAndCache.cache.mem)
pow.dag.paramsAndCache.cache.mem = nil
}
// Make the params and cache for the DAG
paramsAndCache, err := makeParamsAndCache(pow.chainManager, blockNum)
if err != nil {
panic(err)
}
// TODO: On non-SSD disks, loading the DAG from disk takes longer than generating it in memory
pow.paramsAndCache = paramsAndCache
path := path.Join("/", "tmp", "dag")
pow.dag = nil
log.Println("Generating dag")
powlogger.Infoln("Retrieving DAG")
start := time.Now()
file, err := os.Open(path)
if err != nil {
log.Printf("No dag found in '%s'. Generating new dago(takes a while)...", path)
pow.dag = makeDAG(pow.paramsAndCache)
file = pow.writeDagToDisk(pow.dag, seedNum)
powlogger.Infof("No DAG found. Generating new DAG in '%s' (this takes a while)...\n", path)
pow.dag = makeDAG(paramsAndCache)
file = pow.writeDagToDisk(pow.dag, thisEpoch)
pow.dag.file = true
} else {
data, err := ioutil.ReadAll(file)
if err != nil {
panic(err)
powlogger.Infof("DAG load err: %v\n", err)
}
num := binary.BigEndian.Uint64(data[0:8])
if num < seedNum {
log.Printf("Old found. Generating new dag (takes a while)...")
pow.dag = makeDAG(pow.paramsAndCache)
file = pow.writeDagToDisk(pow.dag, seedNum)
if len(data) < 8 {
powlogger.Infof("DAG in '%s' is less than 8 bytes, it must be corrupted. Generating new DAG (this takes a while)...\n", path)
pow.dag = makeDAG(paramsAndCache)
file = pow.writeDagToDisk(pow.dag, thisEpoch)
pow.dag.file = true
} else {
data = data[8:]
pow.dag = &DAG{
dag: unsafe.Pointer(&data[0]),
file: true,
SeedBlockNum: pow.paramsAndCache.SeedBlockNum,
dataEpoch := binary.BigEndian.Uint64(data[0:8])
if dataEpoch < thisEpoch {
powlogger.Infof("DAG in '%s' is stale. Generating new DAG (this takes a while)...\n", path)
pow.dag = makeDAG(paramsAndCache)
file = pow.writeDagToDisk(pow.dag, thisEpoch)
pow.dag.file = true
} else if dataEpoch > thisEpoch {
// FIXME
panic(fmt.Errorf("Saved DAG in '%s' reports to be from future epoch %v (current epoch is %v)\n", path, dataEpoch, thisEpoch))
} else if len(data) != (int(paramsAndCache.params.full_size) + 8) {
powlogger.Infof("DAG in '%s' is corrupted. Generating new DAG (this takes a while)...\n", path)
pow.dag = makeDAG(paramsAndCache)
file = pow.writeDagToDisk(pow.dag, thisEpoch)
pow.dag.file = true
} else {
data = data[8:]
pow.dag = &DAG{
dag: unsafe.Pointer(&data[0]),
file: true,
paramsAndCache: paramsAndCache,
}
}
}
}
log.Println("Took:", time.Since(start))
powlogger.Infoln("Took:", time.Since(start))
file.Close()
}
pow.dagMutex.Unlock()
pow.cacheMutex.Unlock()
}
func New(chainManager pow.ChainManager) *Ethash {
paramsAndCache, err := makeParamsAndCache(chainManager, chainManager.CurrentBlock().NumberU64())
if err != nil {
panic(err)
}
return &Ethash{
turbo: true,
paramsAndCache: makeParamsAndCache(chainManager, chainManager.CurrentBlock().NumberU64()),
paramsAndCache: paramsAndCache,
chainManager: chainManager,
dag: nil,
cacheMutex: new(sync.Mutex),
dagMutex: new(sync.Mutex),
cacheMutex: new(sync.RWMutex),
dagMutex: new(sync.RWMutex),
}
}
func (pow *Ethash) DAGSize() uint64 {
return uint64(pow.paramsAndCache.params.full_size)
return uint64(pow.dag.paramsAndCache.params.full_size)
}
func (pow *Ethash) CacheSize() uint64 {
return uint64(pow.paramsAndCache.params.cache_size)
}
func (pow *Ethash) GetSeedHash(blockNum uint64) []byte {
seednum := GetSeedBlockNum(blockNum)
return pow.chainManager.GetBlockByNumber(seednum).SeedHash()
func GetSeedHash(blockNum uint64) ([]byte, error) {
if blockNum >= epochLength*2048 {
return nil, fmt.Errorf("block number is out of bounds (value %v, limit is %v)", blockNum, epochLength*2048)
}
epoch := blockNum / epochLength
seedHash := make([]byte, 32)
var i uint64
for i = 0; i < 32; i++ {
seedHash[i] = 0
}
for i = 0; i < epoch; i++ {
seedHash = crypto.Sha3(seedHash)
}
return seedHash, nil
}
func (pow *Ethash) Stop() {
@ -224,17 +297,18 @@ func (pow *Ethash) Stop() {
if pow.dag.dag != nil && !pow.dag.file {
C.free(pow.dag.dag)
}
if pow.dag != nil && pow.dag.paramsAndCache != nil && pow.dag.paramsAndCache.cache.mem != nil {
C.free(pow.dag.paramsAndCache.cache.mem)
pow.dag.paramsAndCache.cache.mem = nil
}
pow.dag.dag = nil
}
func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte, []byte) {
//pow.UpdateDAG()
pow.UpdateDAG()
// Not very elegant, multiple mining instances are not supported
//pow.dagMutex.Lock()
//pow.cacheMutex.Lock()
//defer pow.cacheMutex.Unlock()
//defer pow.dagMutex.Unlock()
pow.dagMutex.RLock()
defer pow.dagMutex.RUnlock()
r := rand.New(rand.NewSource(time.Now().UnixNano()))
miningHash := block.HashNoNonce()
@ -246,7 +320,7 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte
nonce := uint64(r.Int63())
cMiningHash := (*C.uint8_t)(unsafe.Pointer(&miningHash[0]))
target := new(big.Int).Div(tt256, diff)
target := new(big.Int).Div(minDifficulty, diff)
var ret C.ethash_return_value
for {
@ -262,14 +336,17 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte
hashes := ((float64(1e9) / float64(elapsed)) * float64(i-starti)) / 1000
pow.HashRate = int64(hashes)
C.ethash_full(&ret, pow.dag.dag, pow.paramsAndCache.params, cMiningHash, C.uint64_t(nonce))
result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
C.ethash_full(&ret, pow.dag.dag, pow.dag.paramsAndCache.params, cMiningHash, C.uint64_t(nonce))
result := common.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
// TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining
if result.Cmp(target) <= 0 {
mixDigest := C.GoBytes(unsafe.Pointer(&ret.mix_hash[0]), C.int(32))
return nonce, mixDigest, pow.GetSeedHash(block.NumberU64())
seedHash, err := GetSeedHash(block.NumberU64()) // This seedhash is useless
if err != nil {
panic(err)
}
return nonce, mixDigest, seedHash
}
nonce += 1
@ -283,32 +360,40 @@ func (pow *Ethash) Search(block pow.Block, stop <-chan struct{}) (uint64, []byte
}
func (pow *Ethash) Verify(block pow.Block) bool {
// Make sure the SeedHash is set correctly
if bytes.Compare(block.SeedHash(), pow.GetSeedHash(block.NumberU64())) != 0 {
return false
}
return pow.verify(block.HashNoNonce(), block.MixDigest(), block.Difficulty(), block.NumberU64(), block.Nonce())
return pow.verify(block.HashNoNonce().Bytes(), block.MixDigest().Bytes(), block.Difficulty(), block.NumberU64(), block.Nonce())
}
func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, blockNum uint64, nonce uint64) bool {
// First check: make sure header, mixDigest, nonce are correct without hitting the DAG
// Make sure the block num is valid
if blockNum >= epochLength*2048 {
powlogger.Infoln(fmt.Sprintf("Block number exceeds limit, invalid (value is %v, limit is %v)",
blockNum, epochLength*2048))
return false
}
// First check: make sure header, mixDigest, nonce are correct without hitting the cache
// This is to prevent DOS attacks
chash := (*C.uint8_t)(unsafe.Pointer(&hash[0]))
cnonce := C.uint64_t(nonce)
target := new(big.Int).Div(tt256, difficulty)
target := new(big.Int).Div(minDifficulty, difficulty)
var pAc *ParamsAndCache
// If its an old block (doesn't use the current cache)
// get the cache for it but don't update (so we don't need the mutex)
// Otherwise, it's the current block or a future.
// Otherwise, it's the current block or a future block.
// If current, updateCache will do nothing.
if GetSeedBlockNum(blockNum) < pow.paramsAndCache.SeedBlockNum {
pAc = makeParamsAndCache(pow.chainManager, blockNum)
if blockNum/epochLength < pow.paramsAndCache.Epoch {
var err error
// If we can't make the params for some reason, this block is invalid
pAc, err = makeParamsAndCache(pow.chainManager, blockNum)
if err != nil {
powlogger.Infoln(err)
return false
}
} else {
pow.updateCache()
pow.cacheMutex.Lock()
defer pow.cacheMutex.Unlock()
pow.UpdateCache(false)
pow.cacheMutex.RLock()
defer pow.cacheMutex.RUnlock()
pAc = pow.paramsAndCache
}
@ -316,7 +401,7 @@ func (pow *Ethash) verify(hash []byte, mixDigest []byte, difficulty *big.Int, bl
C.ethash_light(ret, pAc.cache, pAc.params, chash, cnonce)
result := ethutil.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
result := common.Bytes2Big(C.GoBytes(unsafe.Pointer(&ret.result[0]), C.int(32)))
return result.Cmp(target) <= 0
}

View file

@ -0,0 +1,329 @@
module.exports = [
16776896, 16907456, 17039296, 17170112, 17301056, 17432512, 17563072,
17693888, 17824192, 17955904, 18087488, 18218176, 18349504, 18481088,
18611392, 18742336, 18874304, 19004224, 19135936, 19267264, 19398208,
19529408, 19660096, 19791424, 19922752, 20053952, 20184896, 20315968,
20446912, 20576576, 20709184, 20840384, 20971072, 21102272, 21233216,
21364544, 21494848, 21626816, 21757376, 21887552, 22019392, 22151104,
22281536, 22412224, 22543936, 22675264, 22806464, 22935872, 23068096,
23198272, 23330752, 23459008, 23592512, 23723968, 23854912, 23986112,
24116672, 24247616, 24378688, 24509504, 24640832, 24772544, 24903488,
25034432, 25165376, 25296704, 25427392, 25558592, 25690048, 25820096,
25951936, 26081728, 26214208, 26345024, 26476096, 26606656, 26737472,
26869184, 26998208, 27131584, 27262528, 27393728, 27523904, 27655744,
27786688, 27917888, 28049344, 28179904, 28311488, 28441792, 28573504,
28700864, 28835648, 28966208, 29096768, 29228608, 29359808, 29490752,
29621824, 29752256, 29882816, 30014912, 30144448, 30273728, 30406976,
30538432, 30670784, 30799936, 30932672, 31063744, 31195072, 31325248,
31456192, 31588288, 31719232, 31850432, 31981504, 32110784, 32243392,
32372672, 32505664, 32636608, 32767808, 32897344, 33029824, 33160768,
33289664, 33423296, 33554368, 33683648, 33816512, 33947456, 34076992,
34208704, 34340032, 34471744, 34600256, 34734016, 34864576, 34993984,
35127104, 35258176, 35386688, 35518528, 35650624, 35782336, 35910976,
36044608, 36175808, 36305728, 36436672, 36568384, 36699968, 36830656,
36961984, 37093312, 37223488, 37355072, 37486528, 37617472, 37747904,
37879232, 38009792, 38141888, 38272448, 38403392, 38535104, 38660672,
38795584, 38925632, 39059264, 39190336, 39320768, 39452096, 39581632,
39713984, 39844928, 39974848, 40107968, 40238144, 40367168, 40500032,
40631744, 40762816, 40894144, 41023552, 41155904, 41286208, 41418304,
41547712, 41680448, 41811904, 41942848, 42073792, 42204992, 42334912,
42467008, 42597824, 42729152, 42860096, 42991552, 43122368, 43253696,
43382848, 43515712, 43646912, 43777088, 43907648, 44039104, 44170432,
44302144, 44433344, 44564288, 44694976, 44825152, 44956864, 45088448,
45219008, 45350464, 45481024, 45612608, 45744064, 45874496, 46006208,
46136768, 46267712, 46399424, 46529344, 46660672, 46791488, 46923328,
47053504, 47185856, 47316928, 47447872, 47579072, 47710144, 47839936,
47971648, 48103232, 48234176, 48365248, 48496192, 48627136, 48757312,
48889664, 49020736, 49149248, 49283008, 49413824, 49545152, 49675712,
49807168, 49938368, 50069056, 50200256, 50331584, 50462656, 50593472,
50724032, 50853952, 50986048, 51117632, 51248576, 51379904, 51510848,
51641792, 51773248, 51903296, 52035136, 52164032, 52297664, 52427968,
52557376, 52690112, 52821952, 52952896, 53081536, 53213504, 53344576,
53475776, 53608384, 53738816, 53870528, 54000832, 54131776, 54263744,
54394688, 54525248, 54655936, 54787904, 54918592, 55049152, 55181248,
55312064, 55442752, 55574336, 55705024, 55836224, 55967168, 56097856,
56228672, 56358592, 56490176, 56621888, 56753728, 56884928, 57015488,
57146816, 57278272, 57409216, 57540416, 57671104, 57802432, 57933632,
58064576, 58195264, 58326976, 58457408, 58588864, 58720192, 58849984,
58981696, 59113024, 59243456, 59375552, 59506624, 59637568, 59768512,
59897792, 60030016, 60161984, 60293056, 60423872, 60554432, 60683968,
60817216, 60948032, 61079488, 61209664, 61341376, 61471936, 61602752,
61733696, 61865792, 61996736, 62127808, 62259136, 62389568, 62520512,
62651584, 62781632, 62910784, 63045056, 63176128, 63307072, 63438656,
63569216, 63700928, 63831616, 63960896, 64093888, 64225088, 64355392,
64486976, 64617664, 64748608, 64879424, 65009216, 65142464, 65273792,
65402816, 65535424, 65666752, 65797696, 65927744, 66060224, 66191296,
66321344, 66453056, 66584384, 66715328, 66846656, 66977728, 67108672,
67239104, 67370432, 67501888, 67631296, 67763776, 67895104, 68026304,
68157248, 68287936, 68419264, 68548288, 68681408, 68811968, 68942912,
69074624, 69205568, 69337024, 69467584, 69599168, 69729472, 69861184,
69989824, 70122944, 70253888, 70385344, 70515904, 70647232, 70778816,
70907968, 71040832, 71171648, 71303104, 71432512, 71564992, 71695168,
71826368, 71958464, 72089536, 72219712, 72350144, 72482624, 72613568,
72744512, 72875584, 73006144, 73138112, 73268672, 73400128, 73530944,
73662272, 73793344, 73924544, 74055104, 74185792, 74316992, 74448832,
74579392, 74710976, 74841664, 74972864, 75102784, 75233344, 75364544,
75497024, 75627584, 75759296, 75890624, 76021696, 76152256, 76283072,
76414144, 76545856, 76676672, 76806976, 76937792, 77070016, 77200832,
77331392, 77462464, 77593664, 77725376, 77856448, 77987776, 78118336,
78249664, 78380992, 78511424, 78642496, 78773056, 78905152, 79033664,
79166656, 79297472, 79429568, 79560512, 79690816, 79822784, 79953472,
80084672, 80214208, 80346944, 80477632, 80608576, 80740288, 80870848,
81002048, 81133504, 81264448, 81395648, 81525952, 81657536, 81786304,
81919808, 82050112, 82181312, 82311616, 82443968, 82573376, 82705984,
82835776, 82967744, 83096768, 83230528, 83359552, 83491264, 83622464,
83753536, 83886016, 84015296, 84147776, 84277184, 84409792, 84540608,
84672064, 84803008, 84934336, 85065152, 85193792, 85326784, 85458496,
85589312, 85721024, 85851968, 85982656, 86112448, 86244416, 86370112,
86506688, 86637632, 86769344, 86900672, 87031744, 87162304, 87293632,
87424576, 87555392, 87687104, 87816896, 87947968, 88079168, 88211264,
88341824, 88473152, 88603712, 88735424, 88862912, 88996672, 89128384,
89259712, 89390272, 89521984, 89652544, 89783872, 89914816, 90045376,
90177088, 90307904, 90438848, 90569152, 90700096, 90832832, 90963776,
91093696, 91223744, 91356992, 91486784, 91618496, 91749824, 91880384,
92012224, 92143552, 92273344, 92405696, 92536768, 92666432, 92798912,
92926016, 93060544, 93192128, 93322816, 93453632, 93583936, 93715136,
93845056, 93977792, 94109504, 94240448, 94371776, 94501184, 94632896,
94764224, 94895552, 95023424, 95158208, 95287744, 95420224, 95550016,
95681216, 95811904, 95943872, 96075328, 96203584, 96337856, 96468544,
96599744, 96731072, 96860992, 96992576, 97124288, 97254848, 97385536,
97517248, 97647808, 97779392, 97910464, 98041408, 98172608, 98303168,
98434496, 98565568, 98696768, 98827328, 98958784, 99089728, 99220928,
99352384, 99482816, 99614272, 99745472, 99876416, 100007104,
100138048, 100267072, 100401088, 100529984, 100662592, 100791872,
100925248, 101056064, 101187392, 101317952, 101449408, 101580608,
101711296, 101841728, 101973824, 102104896, 102235712, 102366016,
102498112, 102628672, 102760384, 102890432, 103021888, 103153472,
103284032, 103415744, 103545152, 103677248, 103808576, 103939648,
104070976, 104201792, 104332736, 104462528, 104594752, 104725952,
104854592, 104988608, 105118912, 105247808, 105381184, 105511232,
105643072, 105774784, 105903296, 106037056, 106167872, 106298944,
106429504, 106561472, 106691392, 106822592, 106954304, 107085376,
107216576, 107346368, 107478464, 107609792, 107739712, 107872192,
108003136, 108131392, 108265408, 108396224, 108527168, 108657344,
108789568, 108920384, 109049792, 109182272, 109312576, 109444928,
109572928, 109706944, 109837888, 109969088, 110099648, 110230976,
110362432, 110492992, 110624704, 110755264, 110886208, 111017408,
111148864, 111279296, 111410752, 111541952, 111673024, 111803456,
111933632, 112066496, 112196416, 112328512, 112457792, 112590784,
112715968, 112852672, 112983616, 113114944, 113244224, 113376448,
113505472, 113639104, 113770304, 113901376, 114031552, 114163264,
114294592, 114425536, 114556864, 114687424, 114818624, 114948544,
115080512, 115212224, 115343296, 115473472, 115605184, 115736128,
115867072, 115997248, 116128576, 116260288, 116391488, 116522944,
116652992, 116784704, 116915648, 117046208, 117178304, 117308608,
117440192, 117569728, 117701824, 117833024, 117964096, 118094656,
118225984, 118357312, 118489024, 118617536, 118749632, 118882112,
119012416, 119144384, 119275328, 119406016, 119537344, 119668672,
119798464, 119928896, 120061376, 120192832, 120321728, 120454336,
120584512, 120716608, 120848192, 120979136, 121109056, 121241408,
121372352, 121502912, 121634752, 121764416, 121895744, 122027072,
122157632, 122289088, 122421184, 122550592, 122682944, 122813888,
122945344, 123075776, 123207488, 123338048, 123468736, 123600704,
123731264, 123861952, 123993664, 124124608, 124256192, 124386368,
124518208, 124649024, 124778048, 124911296, 125041088, 125173696,
125303744, 125432896, 125566912, 125696576, 125829056, 125958592,
126090304, 126221248, 126352832, 126483776, 126615232, 126746432,
126876608, 127008704, 127139392, 127270336, 127401152, 127532224,
127663552, 127794752, 127925696, 128055232, 128188096, 128319424,
128449856, 128581312, 128712256, 128843584, 128973632, 129103808,
129236288, 129365696, 129498944, 129629888, 129760832, 129892288,
130023104, 130154048, 130283968, 130416448, 130547008, 130678336,
130807616, 130939456, 131071552, 131202112, 131331776, 131464384,
131594048, 131727296, 131858368, 131987392, 132120256, 132250816,
132382528, 132513728, 132644672, 132774976, 132905792, 133038016,
133168832, 133299392, 133429312, 133562048, 133692992, 133823296,
133954624, 134086336, 134217152, 134348608, 134479808, 134607296,
134741056, 134872384, 135002944, 135134144, 135265472, 135396544,
135527872, 135659072, 135787712, 135921472, 136052416, 136182848,
136313792, 136444864, 136576448, 136707904, 136837952, 136970048,
137099584, 137232064, 137363392, 137494208, 137625536, 137755712,
137887424, 138018368, 138149824, 138280256, 138411584, 138539584,
138672832, 138804928, 138936128, 139066688, 139196864, 139328704,
139460032, 139590208, 139721024, 139852864, 139984576, 140115776,
140245696, 140376512, 140508352, 140640064, 140769856, 140902336,
141032768, 141162688, 141294016, 141426496, 141556544, 141687488,
141819584, 141949888, 142080448, 142212544, 142342336, 142474432,
142606144, 142736192, 142868288, 142997824, 143129408, 143258944,
143392448, 143523136, 143653696, 143785024, 143916992, 144045632,
144177856, 144309184, 144440768, 144570688, 144701888, 144832448,
144965056, 145096384, 145227584, 145358656, 145489856, 145620928,
145751488, 145883072, 146011456, 146144704, 146275264, 146407232,
146538176, 146668736, 146800448, 146931392, 147062336, 147193664,
147324224, 147455936, 147586624, 147717056, 147848768, 147979456,
148110784, 148242368, 148373312, 148503232, 148635584, 148766144,
148897088, 149028416, 149159488, 149290688, 149420224, 149551552,
149683136, 149814976, 149943616, 150076352, 150208064, 150338624,
150470464, 150600256, 150732224, 150862784, 150993088, 151125952,
151254976, 151388096, 151519168, 151649728, 151778752, 151911104,
152042944, 152174144, 152304704, 152435648, 152567488, 152698816,
152828992, 152960576, 153091648, 153222976, 153353792, 153484096,
153616192, 153747008, 153878336, 154008256, 154139968, 154270912,
154402624, 154533824, 154663616, 154795712, 154926272, 155057984,
155188928, 155319872, 155450816, 155580608, 155712064, 155843392,
155971136, 156106688, 156237376, 156367424, 156499264, 156630976,
156761536, 156892352, 157024064, 157155008, 157284416, 157415872,
157545536, 157677248, 157810496, 157938112, 158071744, 158203328,
158334656, 158464832, 158596288, 158727616, 158858048, 158988992,
159121216, 159252416, 159381568, 159513152, 159645632, 159776192,
159906496, 160038464, 160169536, 160300352, 160430656, 160563008,
160693952, 160822208, 160956352, 161086784, 161217344, 161349184,
161480512, 161611456, 161742272, 161873216, 162002752, 162135872,
162266432, 162397888, 162529216, 162660032, 162790976, 162922048,
163052096, 163184576, 163314752, 163446592, 163577408, 163707968,
163839296, 163969984, 164100928, 164233024, 164364224, 164494912,
164625856, 164756672, 164887616, 165019072, 165150016, 165280064,
165412672, 165543104, 165674944, 165805888, 165936832, 166067648,
166198336, 166330048, 166461248, 166591552, 166722496, 166854208,
166985408, 167116736, 167246656, 167378368, 167508416, 167641024,
167771584, 167903168, 168034112, 168164032, 168295744, 168427456,
168557632, 168688448, 168819136, 168951616, 169082176, 169213504,
169344832, 169475648, 169605952, 169738048, 169866304, 169999552,
170131264, 170262464, 170393536, 170524352, 170655424, 170782016,
170917696, 171048896, 171179072, 171310784, 171439936, 171573184,
171702976, 171835072, 171966272, 172097216, 172228288, 172359232,
172489664, 172621376, 172747712, 172883264, 173014208, 173144512,
173275072, 173407424, 173539136, 173669696, 173800768, 173931712,
174063424, 174193472, 174325696, 174455744, 174586816, 174718912,
174849728, 174977728, 175109696, 175242688, 175374272, 175504832,
175636288, 175765696, 175898432, 176028992, 176159936, 176291264,
176422592, 176552512, 176684864, 176815424, 176946496, 177076544,
177209152, 177340096, 177470528, 177600704, 177731648, 177864256,
177994816, 178126528, 178257472, 178387648, 178518464, 178650176,
178781888, 178912064, 179044288, 179174848, 179305024, 179436736,
179568448, 179698496, 179830208, 179960512, 180092608, 180223808,
180354752, 180485696, 180617152, 180748096, 180877504, 181009984,
181139264, 181272512, 181402688, 181532608, 181663168, 181795136,
181926592, 182057536, 182190016, 182320192, 182451904, 182582336,
182713792, 182843072, 182976064, 183107264, 183237056, 183368384,
183494848, 183631424, 183762752, 183893824, 184024768, 184154816,
184286656, 184417984, 184548928, 184680128, 184810816, 184941248,
185072704, 185203904, 185335616, 185465408, 185596352, 185727296,
185859904, 185989696, 186121664, 186252992, 186383552, 186514112,
186645952, 186777152, 186907328, 187037504, 187170112, 187301824,
187429184, 187562048, 187693504, 187825472, 187957184, 188087104,
188218304, 188349376, 188481344, 188609728, 188743616, 188874304,
189005248, 189136448, 189265088, 189396544, 189528128, 189660992,
189791936, 189923264, 190054208, 190182848, 190315072, 190447424,
190577984, 190709312, 190840768, 190971328, 191102656, 191233472,
191364032, 191495872, 191626816, 191758016, 191888192, 192020288,
192148928, 192282176, 192413504, 192542528, 192674752, 192805952,
192937792, 193068608, 193198912, 193330496, 193462208, 193592384,
193723456, 193854272, 193985984, 194116672, 194247232, 194379712,
194508352, 194641856, 194772544, 194900672, 195035072, 195166016,
195296704, 195428032, 195558592, 195690304, 195818176, 195952576,
196083392, 196214336, 196345792, 196476736, 196607552, 196739008,
196869952, 197000768, 197130688, 197262784, 197394368, 197523904,
197656384, 197787584, 197916608, 198049472, 198180544, 198310208,
198442432, 198573632, 198705088, 198834368, 198967232, 199097792,
199228352, 199360192, 199491392, 199621696, 199751744, 199883968,
200014016, 200146624, 200276672, 200408128, 200540096, 200671168,
200801984, 200933312, 201062464, 201194944, 201326144, 201457472,
201588544, 201719744, 201850816, 201981632, 202111552, 202244032,
202374464, 202505152, 202636352, 202767808, 202898368, 203030336,
203159872, 203292608, 203423296, 203553472, 203685824, 203816896,
203947712, 204078272, 204208192, 204341056, 204472256, 204603328,
204733888, 204864448, 204996544, 205125568, 205258304, 205388864,
205517632, 205650112, 205782208, 205913536, 206044736, 206176192,
206307008, 206434496, 206569024, 206700224, 206831168, 206961856,
207093056, 207223616, 207355328, 207486784, 207616832, 207749056,
207879104, 208010048, 208141888, 208273216, 208404032, 208534336,
208666048, 208796864, 208927424, 209059264, 209189824, 209321792,
209451584, 209582656, 209715136, 209845568, 209976896, 210106432,
210239296, 210370112, 210501568, 210630976, 210763712, 210894272,
211024832, 211156672, 211287616, 211418176, 211549376, 211679296,
211812032, 211942592, 212074432, 212204864, 212334016, 212467648,
212597824, 212727616, 212860352, 212991424, 213120832, 213253952,
213385024, 213515584, 213645632, 213777728, 213909184, 214040128,
214170688, 214302656, 214433728, 214564544, 214695232, 214826048,
214956992, 215089088, 215219776, 215350592, 215482304, 215613248,
215743552, 215874752, 216005312, 216137024, 216267328, 216399296,
216530752, 216661696, 216790592, 216923968, 217054528, 217183168,
217316672, 217448128, 217579072, 217709504, 217838912, 217972672,
218102848, 218233024, 218364736, 218496832, 218627776, 218759104,
218888896, 219021248, 219151936, 219281728, 219413056, 219545024,
219675968, 219807296, 219938624, 220069312, 220200128, 220331456,
220461632, 220592704, 220725184, 220855744, 220987072, 221117888,
221249216, 221378368, 221510336, 221642048, 221772736, 221904832,
222031808, 222166976, 222297536, 222428992, 222559936, 222690368,
222820672, 222953152, 223083968, 223213376, 223345984, 223476928,
223608512, 223738688, 223869376, 224001472, 224132672, 224262848,
224394944, 224524864, 224657344, 224788288, 224919488, 225050432,
225181504, 225312704, 225443776, 225574592, 225704768, 225834176,
225966784, 226097216, 226229824, 226360384, 226491712, 226623424,
226754368, 226885312, 227015104, 227147456, 227278528, 227409472,
227539904, 227669696, 227802944, 227932352, 228065216, 228196288,
228326464, 228457792, 228588736, 228720064, 228850112, 228981056,
229113152, 229243328, 229375936, 229505344, 229636928, 229769152,
229894976, 230030272, 230162368, 230292416, 230424512, 230553152,
230684864, 230816704, 230948416, 231079616, 231210944, 231342016,
231472448, 231603776, 231733952, 231866176, 231996736, 232127296,
232259392, 232388672, 232521664, 232652608, 232782272, 232914496,
233043904, 233175616, 233306816, 233438528, 233569984, 233699776,
233830592, 233962688, 234092224, 234221888, 234353984, 234485312,
234618304, 234749888, 234880832, 235011776, 235142464, 235274048,
235403456, 235535936, 235667392, 235797568, 235928768, 236057152,
236190272, 236322752, 236453312, 236583616, 236715712, 236846528,
236976448, 237108544, 237239104, 237371072, 237501632, 237630784,
237764416, 237895232, 238026688, 238157632, 238286912, 238419392,
238548032, 238681024, 238812608, 238941632, 239075008, 239206336,
239335232, 239466944, 239599168, 239730496, 239861312, 239992384,
240122816, 240254656, 240385856, 240516928, 240647872, 240779072,
240909632, 241040704, 241171904, 241302848, 241433408, 241565248,
241696192, 241825984, 241958848, 242088256, 242220224, 242352064,
242481856, 242611648, 242744896, 242876224, 243005632, 243138496,
243268672, 243400384, 243531712, 243662656, 243793856, 243924544,
244054592, 244187072, 244316608, 244448704, 244580032, 244710976,
244841536, 244972864, 245104448, 245233984, 245365312, 245497792,
245628736, 245759936, 245889856, 246021056, 246152512, 246284224,
246415168, 246545344, 246675904, 246808384, 246939584, 247070144,
247199552, 247331648, 247463872, 247593536, 247726016, 247857088,
247987648, 248116928, 248249536, 248380736, 248512064, 248643008,
248773312, 248901056, 249036608, 249167552, 249298624, 249429184,
249560512, 249692096, 249822784, 249954112, 250085312, 250215488,
250345792, 250478528, 250608704, 250739264, 250870976, 251002816,
251133632, 251263552, 251395136, 251523904, 251657792, 251789248,
251919424, 252051392, 252182464, 252313408, 252444224, 252575552,
252706624, 252836032, 252968512, 253099712, 253227584, 253361728,
253493056, 253623488, 253754432, 253885504, 254017216, 254148032,
254279488, 254410432, 254541376, 254672576, 254803264, 254933824,
255065792, 255196736, 255326528, 255458752, 255589952, 255721408,
255851072, 255983296, 256114624, 256244416, 256374208, 256507712,
256636096, 256768832, 256900544, 257031616, 257162176, 257294272,
257424448, 257555776, 257686976, 257818432, 257949632, 258079552,
258211136, 258342464, 258473408, 258603712, 258734656, 258867008,
258996544, 259127744, 259260224, 259391296, 259522112, 259651904,
259784384, 259915328, 260045888, 260175424, 260308544, 260438336,
260570944, 260700992, 260832448, 260963776, 261092672, 261226304,
261356864, 261487936, 261619648, 261750592, 261879872, 262011968,
262143424, 262274752, 262404416, 262537024, 262667968, 262799296,
262928704, 263061184, 263191744, 263322944, 263454656, 263585216,
263716672, 263847872, 263978944, 264108608, 264241088, 264371648,
264501184, 264632768, 264764096, 264895936, 265024576, 265158464,
265287488, 265418432, 265550528, 265681216, 265813312, 265943488,
266075968, 266206144, 266337728, 266468032, 266600384, 266731072,
266862272, 266993344, 267124288, 267255616, 267386432, 267516992,
267648704, 267777728, 267910592, 268040512, 268172096, 268302784,
268435264, 268566208, 268696256, 268828096, 268959296, 269090368,
269221312, 269352256, 269482688, 269614784, 269745856, 269876416,
270007616, 270139328, 270270272, 270401216, 270531904, 270663616,
270791744, 270924736, 271056832, 271186112, 271317184, 271449536,
271580992, 271711936, 271843136, 271973056, 272105408, 272236352,
272367296, 272498368, 272629568, 272759488, 272891456, 273022784,
273153856, 273284672, 273415616, 273547072, 273677632, 273808448,
273937088, 274071488, 274200896, 274332992, 274463296, 274595392,
274726208, 274857536, 274988992, 275118656, 275250496, 275382208,
275513024, 275643968, 275775296, 275906368, 276037184, 276167872,
276297664, 276429376, 276560576, 276692672, 276822976, 276955072,
277085632, 277216832, 277347008, 277478848, 277609664, 277740992,
277868608, 278002624, 278134336, 278265536, 278395328, 278526784,
278657728, 278789824, 278921152, 279052096, 279182912, 279313088,
279443776, 279576256, 279706048, 279838528, 279969728, 280099648,
280230976, 280361408, 280493632, 280622528, 280755392, 280887104,
281018176, 281147968, 281278912, 281411392, 281542592, 281673152,
281803712, 281935552, 282066496, 282197312, 282329024, 282458816,
282590272, 282720832, 282853184, 282983744, 283115072, 283246144,
283377344, 283508416, 283639744, 283770304, 283901504, 284032576,
284163136, 284294848, 284426176, 284556992, 284687296, 284819264,
284950208, 285081536
];

View file

@ -0,0 +1,412 @@
module.exports = [
1073739904, 1082130304, 1090514816, 1098906752, 1107293056,
1115684224, 1124070016, 1132461952, 1140849536, 1149232768,
1157627776, 1166013824, 1174404736, 1182786944, 1191180416,
1199568512, 1207958912, 1216345216, 1224732032, 1233124736,
1241513344, 1249902464, 1258290304, 1266673792, 1275067264,
1283453312, 1291844992, 1300234112, 1308619904, 1317010048,
1325397376, 1333787776, 1342176128, 1350561664, 1358954368,
1367339392, 1375731584, 1384118144, 1392507008, 1400897408,
1409284736, 1417673344, 1426062464, 1434451072, 1442839168,
1451229056, 1459615616, 1468006016, 1476394112, 1484782976,
1493171584, 1501559168, 1509948032, 1518337664, 1526726528,
1535114624, 1543503488, 1551892096, 1560278656, 1568669056,
1577056384, 1585446272, 1593831296, 1602219392, 1610610304,
1619000192, 1627386752, 1635773824, 1644164224, 1652555648,
1660943488, 1669332608, 1677721216, 1686109312, 1694497664,
1702886272, 1711274624, 1719661184, 1728047744, 1736434816,
1744829056, 1753218944, 1761606272, 1769995904, 1778382464,
1786772864, 1795157888, 1803550592, 1811937664, 1820327552,
1828711552, 1837102976, 1845488768, 1853879936, 1862269312,
1870656896, 1879048064, 1887431552, 1895825024, 1904212096,
1912601216, 1920988544, 1929379456, 1937765504, 1946156672,
1954543232, 1962932096, 1971321728, 1979707264, 1988093056,
1996487552, 2004874624, 2013262208, 2021653888, 2030039936,
2038430848, 2046819968, 2055208576, 2063596672, 2071981952,
2080373632, 2088762752, 2097149056, 2105539712, 2113928576,
2122315136, 2130700672, 2139092608, 2147483264, 2155872128,
2164257664, 2172642176, 2181035392, 2189426048, 2197814912,
2206203008, 2214587264, 2222979712, 2231367808, 2239758208,
2248145024, 2256527744, 2264922752, 2273312128, 2281701248,
2290086272, 2298476672, 2306867072, 2315251072, 2323639168,
2332032128, 2340420224, 2348808064, 2357196416, 2365580416,
2373966976, 2382363008, 2390748544, 2399139968, 2407530368,
2415918976, 2424307328, 2432695424, 2441084288, 2449472384,
2457861248, 2466247808, 2474637184, 2483026816, 2491414144,
2499803776, 2508191872, 2516582272, 2524970368, 2533359232,
2541743488, 2550134144, 2558525056, 2566913408, 2575301504,
2583686528, 2592073856, 2600467328, 2608856192, 2617240448,
2625631616, 2634022016, 2642407552, 2650796416, 2659188352,
2667574912, 2675965312, 2684352896, 2692738688, 2701130624,
2709518464, 2717907328, 2726293376, 2734685056, 2743073152,
2751462016, 2759851648, 2768232832, 2776625536, 2785017728,
2793401984, 2801794432, 2810182016, 2818571648, 2826959488,
2835349376, 2843734144, 2852121472, 2860514432, 2868900992,
2877286784, 2885676928, 2894069632, 2902451584, 2910843008,
2919234688, 2927622784, 2936011648, 2944400768, 2952789376,
2961177728, 2969565568, 2977951616, 2986338944, 2994731392,
3003120256, 3011508352, 3019895936, 3028287104, 3036675968,
3045063808, 3053452928, 3061837696, 3070228352, 3078615424,
3087003776, 3095394944, 3103782272, 3112173184, 3120562048,
3128944768, 3137339264, 3145725056, 3154109312, 3162505088,
3170893184, 3179280256, 3187669376, 3196056704, 3204445568,
3212836736, 3221224064, 3229612928, 3238002304, 3246391168,
3254778496, 3263165824, 3271556224, 3279944576, 3288332416,
3296719232, 3305110912, 3313500032, 3321887104, 3330273152,
3338658944, 3347053184, 3355440512, 3363827072, 3372220288,
3380608384, 3388997504, 3397384576, 3405774208, 3414163072,
3422551936, 3430937984, 3439328384, 3447714176, 3456104576,
3464493952, 3472883584, 3481268864, 3489655168, 3498048896,
3506434432, 3514826368, 3523213952, 3531603584, 3539987072,
3548380288, 3556763264, 3565157248, 3573545344, 3581934464,
3590324096, 3598712704, 3607098752, 3615488384, 3623877248,
3632265856, 3640646528, 3649043584, 3657430144, 3665821568,
3674207872, 3682597504, 3690984832, 3699367808, 3707764352,
3716152448, 3724541056, 3732925568, 3741318016, 3749706368,
3758091136, 3766481536, 3774872704, 3783260032, 3791650432,
3800036224, 3808427648, 3816815488, 3825204608, 3833592704,
3841981568, 3850370432, 3858755968, 3867147904, 3875536256,
3883920512, 3892313728, 3900702592, 3909087872, 3917478784,
3925868416, 3934256512, 3942645376, 3951032192, 3959422336,
3967809152, 3976200064, 3984588416, 3992974976, 4001363584,
4009751168, 4018141312, 4026530432, 4034911616, 4043308928,
4051695488, 4060084352, 4068472448, 4076862848, 4085249408,
4093640576, 4102028416, 4110413696, 4118805632, 4127194496,
4135583104, 4143971968, 4152360832, 4160746112, 4169135744,
4177525888, 4185912704, 4194303616, 4202691968, 4211076736,
4219463552, 4227855488, 4236246656, 4244633728, 4253022848,
4261412224, 4269799808, 4278184832, 4286578048, 4294962304,
4303349632, 4311743104, 4320130432, 4328521088, 4336909184,
4345295488, 4353687424, 4362073472, 4370458496, 4378852736,
4387238528, 4395630208, 4404019072, 4412407424, 4420790656,
4429182848, 4437571456, 4445962112, 4454344064, 4462738048,
4471119232, 4479516544, 4487904128, 4496289664, 4504682368,
4513068416, 4521459584, 4529846144, 4538232704, 4546619776,
4555010176, 4563402112, 4571790208, 4580174464, 4588567936,
4596957056, 4605344896, 4613734016, 4622119808, 4630511488,
4638898816, 4647287936, 4655675264, 4664065664, 4672451968,
4680842624, 4689231488, 4697620352, 4706007424, 4714397056,
4722786176, 4731173248, 4739562368, 4747951744, 4756340608,
4764727936, 4773114496, 4781504384, 4789894784, 4798283648,
4806667648, 4815059584, 4823449472, 4831835776, 4840226176,
4848612224, 4857003392, 4865391488, 4873780096, 4882169728,
4890557312, 4898946944, 4907333248, 4915722368, 4924110976,
4932499328, 4940889728, 4949276032, 4957666432, 4966054784,
4974438016, 4982831488, 4991221376, 4999607168, 5007998848,
5016386432, 5024763776, 5033164672, 5041544576, 5049941888,
5058329728, 5066717056, 5075107456, 5083494272, 5091883904,
5100273536, 5108662144, 5117048192, 5125436032, 5133827456,
5142215296, 5150605184, 5158993024, 5167382144, 5175769472,
5184157568, 5192543872, 5200936064, 5209324928, 5217711232,
5226102656, 5234490496, 5242877312, 5251263872, 5259654016,
5268040832, 5276434304, 5284819328, 5293209728, 5301598592,
5309986688, 5318374784, 5326764416, 5335151488, 5343542144,
5351929472, 5360319872, 5368706944, 5377096576, 5385484928,
5393871232, 5402263424, 5410650496, 5419040384, 5427426944,
5435816576, 5444205952, 5452594816, 5460981376, 5469367936,
5477760896, 5486148736, 5494536832, 5502925952, 5511315328,
5519703424, 5528089984, 5536481152, 5544869504, 5553256064,
5561645696, 5570032768, 5578423936, 5586811264, 5595193216,
5603585408, 5611972736, 5620366208, 5628750464, 5637143936,
5645528192, 5653921408, 5662310272, 5670694784, 5679082624,
5687474048, 5695864448, 5704251008, 5712641408, 5721030272,
5729416832, 5737806208, 5746194304, 5754583936, 5762969984,
5771358592, 5779748224, 5788137856, 5796527488, 5804911232,
5813300608, 5821692544, 5830082176, 5838468992, 5846855552,
5855247488, 5863636096, 5872024448, 5880411008, 5888799872,
5897186432, 5905576832, 5913966976, 5922352768, 5930744704,
5939132288, 5947522432, 5955911296, 5964299392, 5972688256,
5981074304, 5989465472, 5997851008, 6006241408, 6014627968,
6023015552, 6031408256, 6039796096, 6048185216, 6056574848,
6064963456, 6073351808, 6081736064, 6090128768, 6098517632,
6106906496, 6115289216, 6123680896, 6132070016, 6140459648,
6148849024, 6157237376, 6165624704, 6174009728, 6182403712,
6190792064, 6199176064, 6207569792, 6215952256, 6224345216,
6232732544, 6241124224, 6249510272, 6257899136, 6266287744,
6274676864, 6283065728, 6291454336, 6299843456, 6308232064,
6316620928, 6325006208, 6333395584, 6341784704, 6350174848,
6358562176, 6366951296, 6375337856, 6383729536, 6392119168,
6400504192, 6408895616, 6417283456, 6425673344, 6434059136,
6442444672, 6450837376, 6459223424, 6467613056, 6476004224,
6484393088, 6492781952, 6501170048, 6509555072, 6517947008,
6526336384, 6534725504, 6543112832, 6551500672, 6559888768,
6568278656, 6576662912, 6585055616, 6593443456, 6601834112,
6610219648, 6618610304, 6626999168, 6635385472, 6643777408,
6652164224, 6660552832, 6668941952, 6677330048, 6685719424,
6694107776, 6702493568, 6710882176, 6719274112, 6727662976,
6736052096, 6744437632, 6752825984, 6761213824, 6769604224,
6777993856, 6786383488, 6794770816, 6803158144, 6811549312,
6819937664, 6828326528, 6836706176, 6845101696, 6853491328,
6861880448, 6870269312, 6878655104, 6887046272, 6895433344,
6903822208, 6912212864, 6920596864, 6928988288, 6937377152,
6945764992, 6954149248, 6962544256, 6970928768, 6979317376,
6987709312, 6996093824, 7004487296, 7012875392, 7021258624,
7029652352, 7038038912, 7046427776, 7054818944, 7063207808,
7071595136, 7079980928, 7088372608, 7096759424, 7105149824,
7113536896, 7121928064, 7130315392, 7138699648, 7147092352,
7155479168, 7163865728, 7172249984, 7180648064, 7189036672,
7197424768, 7205810816, 7214196608, 7222589824, 7230975104,
7239367552, 7247755904, 7256145536, 7264533376, 7272921472,
7281308032, 7289694848, 7298088832, 7306471808, 7314864512,
7323253888, 7331643008, 7340029568, 7348419712, 7356808832,
7365196672, 7373585792, 7381973888, 7390362752, 7398750592,
7407138944, 7415528576, 7423915648, 7432302208, 7440690304,
7449080192, 7457472128, 7465860992, 7474249088, 7482635648,
7491023744, 7499412608, 7507803008, 7516192384, 7524579968,
7532967296, 7541358464, 7549745792, 7558134656, 7566524032,
7574912896, 7583300992, 7591690112, 7600075136, 7608466816,
7616854912, 7625244544, 7633629824, 7642020992, 7650410368,
7658794112, 7667187328, 7675574912, 7683961984, 7692349568,
7700739712, 7709130368, 7717519232, 7725905536, 7734295424,
7742683264, 7751069056, 7759457408, 7767849088, 7776238208,
7784626816, 7793014912, 7801405312, 7809792128, 7818179968,
7826571136, 7834957184, 7843347328, 7851732352, 7860124544,
7868512384, 7876902016, 7885287808, 7893679744, 7902067072,
7910455936, 7918844288, 7927230848, 7935622784, 7944009344,
7952400256, 7960786048, 7969176704, 7977565312, 7985953408,
7994339968, 8002730368, 8011119488, 8019508096, 8027896192,
8036285056, 8044674688, 8053062272, 8061448832, 8069838464,
8078227328, 8086616704, 8095006592, 8103393664, 8111783552,
8120171392, 8128560256, 8136949376, 8145336704, 8153726848,
8162114944, 8170503296, 8178891904, 8187280768, 8195669632,
8204058496, 8212444544, 8220834176, 8229222272, 8237612672,
8246000768, 8254389376, 8262775168, 8271167104, 8279553664,
8287944064, 8296333184, 8304715136, 8313108352, 8321497984,
8329885568, 8338274432, 8346663296, 8355052928, 8363441536,
8371828352, 8380217984, 8388606592, 8396996224, 8405384576,
8413772672, 8422161536, 8430549376, 8438939008, 8447326592,
8455715456, 8464104832, 8472492928, 8480882048, 8489270656,
8497659776, 8506045312, 8514434944, 8522823808, 8531208832,
8539602304, 8547990656, 8556378752, 8564768384, 8573154176,
8581542784, 8589933952, 8598322816, 8606705024, 8615099264,
8623487872, 8631876992, 8640264064, 8648653952, 8657040256,
8665430656, 8673820544, 8682209152, 8690592128, 8698977152,
8707374464, 8715763328, 8724151424, 8732540032, 8740928384,
8749315712, 8757704576, 8766089344, 8774480768, 8782871936,
8791260032, 8799645824, 8808034432, 8816426368, 8824812928,
8833199488, 8841591424, 8849976448, 8858366336, 8866757248,
8875147136, 8883532928, 8891923328, 8900306816, 8908700288,
8917088384, 8925478784, 8933867392, 8942250368, 8950644608,
8959032704, 8967420544, 8975809664, 8984197504, 8992584064,
9000976256, 9009362048, 9017752448, 9026141312, 9034530688,
9042917504, 9051307904, 9059694208, 9068084864, 9076471424,
9084861824, 9093250688, 9101638528, 9110027648, 9118416512,
9126803584, 9135188096, 9143581312, 9151969664, 9160356224,
9168747136, 9177134464, 9185525632, 9193910144, 9202302848,
9210690688, 9219079552, 9227465344, 9235854464, 9244244864,
9252633472, 9261021824, 9269411456, 9277799296, 9286188928,
9294574208, 9302965888, 9311351936, 9319740032, 9328131968,
9336516736, 9344907392, 9353296768, 9361685888, 9370074752,
9378463616, 9386849408, 9395239808, 9403629184, 9412016512,
9420405376, 9428795008, 9437181568, 9445570688, 9453960832,
9462346624, 9470738048, 9479121536, 9487515008, 9495903616,
9504289664, 9512678528, 9521067904, 9529456256, 9537843584,
9546233728, 9554621312, 9563011456, 9571398784, 9579788672,
9588178304, 9596567168, 9604954496, 9613343104, 9621732992,
9630121856, 9638508416, 9646898816, 9655283584, 9663675776,
9672061312, 9680449664, 9688840064, 9697230464, 9705617536,
9714003584, 9722393984, 9730772608, 9739172224, 9747561088,
9755945344, 9764338816, 9772726144, 9781116544, 9789503872,
9797892992, 9806282624, 9814670464, 9823056512, 9831439232,
9839833984, 9848224384, 9856613504, 9865000576, 9873391232,
9881772416, 9890162816, 9898556288, 9906940544, 9915333248,
9923721088, 9932108672, 9940496512, 9948888448, 9957276544,
9965666176, 9974048384, 9982441088, 9990830464, 9999219584,
10007602816, 10015996544, 10024385152, 10032774016, 10041163648,
10049548928, 10057940096, 10066329472, 10074717824, 10083105152,
10091495296, 10099878784, 10108272256, 10116660608, 10125049216,
10133437312, 10141825664, 10150213504, 10158601088, 10166991232,
10175378816, 10183766144, 10192157312, 10200545408, 10208935552,
10217322112, 10225712768, 10234099328, 10242489472, 10250876032,
10259264896, 10267656064, 10276042624, 10284429184, 10292820352,
10301209472, 10309598848, 10317987712, 10326375296, 10334763392,
10343153536, 10351541632, 10359930752, 10368318592, 10376707456,
10385096576, 10393484672, 10401867136, 10410262144, 10418647424,
10427039104, 10435425664, 10443810176, 10452203648, 10460589952,
10468982144, 10477369472, 10485759104, 10494147712, 10502533504,
10510923392, 10519313536, 10527702656, 10536091264, 10544478592,
10552867712, 10561255808, 10569642368, 10578032768, 10586423168,
10594805632, 10603200128, 10611588992, 10619976064, 10628361344,
10636754048, 10645143424, 10653531776, 10661920384, 10670307968,
10678696832, 10687086464, 10695475072, 10703863168, 10712246144,
10720639616, 10729026688, 10737414784, 10745806208, 10754190976,
10762581376, 10770971264, 10779356288, 10787747456, 10796135552,
10804525184, 10812915584, 10821301888, 10829692288, 10838078336,
10846469248, 10854858368, 10863247232, 10871631488, 10880023424,
10888412032, 10896799616, 10905188992, 10913574016, 10921964672,
10930352768, 10938742912, 10947132544, 10955518592, 10963909504,
10972298368, 10980687488, 10989074816, 10997462912, 11005851776,
11014241152, 11022627712, 11031017344, 11039403904, 11047793024,
11056184704, 11064570752, 11072960896, 11081343872, 11089737856,
11098128256, 11106514816, 11114904448, 11123293568, 11131680128,
11140065152, 11148458368, 11156845696, 11165236864, 11173624192,
11182013824, 11190402688, 11198790784, 11207179136, 11215568768,
11223957376, 11232345728, 11240734592, 11249122688, 11257511296,
11265899648, 11274285952, 11282675584, 11291065472, 11299452544,
11307842432, 11316231296, 11324616832, 11333009024, 11341395584,
11349782656, 11358172288, 11366560384, 11374950016, 11383339648,
11391721856, 11400117376, 11408504192, 11416893568, 11425283456,
11433671552, 11442061184, 11450444672, 11458837888, 11467226752,
11475611776, 11484003968, 11492392064, 11500780672, 11509169024,
11517550976, 11525944448, 11534335616, 11542724224, 11551111808,
11559500672, 11567890304, 11576277376, 11584667008, 11593056128,
11601443456, 11609830016, 11618221952, 11626607488, 11634995072,
11643387776, 11651775104, 11660161664, 11668552576, 11676940928,
11685330304, 11693718656, 11702106496, 11710496128, 11718882688,
11727273088, 11735660416, 11744050048, 11752437376, 11760824704,
11769216128, 11777604736, 11785991296, 11794381952, 11802770048,
11811157888, 11819548544, 11827932544, 11836324736, 11844713344,
11853100928, 11861486464, 11869879936, 11878268032, 11886656896,
11895044992, 11903433088, 11911822976, 11920210816, 11928600448,
11936987264, 11945375872, 11953761152, 11962151296, 11970543488,
11978928512, 11987320448, 11995708288, 12004095104, 12012486272,
12020875136, 12029255552, 12037652096, 12046039168, 12054429568,
12062813824, 12071206528, 12079594624, 12087983744, 12096371072,
12104759936, 12113147264, 12121534592, 12129924992, 12138314624,
12146703232, 12155091584, 12163481216, 12171864704, 12180255872,
12188643968, 12197034112, 12205424512, 12213811328, 12222199424,
12230590336, 12238977664, 12247365248, 12255755392, 12264143488,
12272531584, 12280920448, 12289309568, 12297694592, 12306086528,
12314475392, 12322865024, 12331253632, 12339640448, 12348029312,
12356418944, 12364805248, 12373196672, 12381580928, 12389969024,
12398357632, 12406750592, 12415138432, 12423527552, 12431916416,
12440304512, 12448692352, 12457081216, 12465467776, 12473859968,
12482245504, 12490636672, 12499025536, 12507411584, 12515801728,
12524190592, 12532577152, 12540966272, 12549354368, 12557743232,
12566129536, 12574523264, 12582911872, 12591299456, 12599688064,
12608074624, 12616463488, 12624845696, 12633239936, 12641631616,
12650019968, 12658407296, 12666795136, 12675183232, 12683574656,
12691960192, 12700350592, 12708740224, 12717128576, 12725515904,
12733906816, 12742295168, 12750680192, 12759071872, 12767460736,
12775848832, 12784236928, 12792626816, 12801014656, 12809404288,
12817789312, 12826181504, 12834568832, 12842954624, 12851345792,
12859732352, 12868122496, 12876512128, 12884901248, 12893289088,
12901672832, 12910067584, 12918455168, 12926842496, 12935232896,
12943620736, 12952009856, 12960396928, 12968786816, 12977176192,
12985563776, 12993951104, 13002341504, 13010730368, 13019115392,
13027506304, 13035895168, 13044272512, 13052673152, 13061062528,
13069446272, 13077838976, 13086227072, 13094613632, 13103000192,
13111393664, 13119782528, 13128157568, 13136559232, 13144945024,
13153329536, 13161724288, 13170111872, 13178502784, 13186884736,
13195279744, 13203667072, 13212057472, 13220445824, 13228832128,
13237221248, 13245610624, 13254000512, 13262388352, 13270777472,
13279166336, 13287553408, 13295943296, 13304331904, 13312719488,
13321108096, 13329494656, 13337885824, 13346274944, 13354663808,
13363051136, 13371439232, 13379825024, 13388210816, 13396605056,
13404995456, 13413380224, 13421771392, 13430159744, 13438546048,
13446937216, 13455326848, 13463708288, 13472103808, 13480492672,
13488875648, 13497269888, 13505657728, 13514045312, 13522435712,
13530824576, 13539210112, 13547599232, 13555989376, 13564379008,
13572766336, 13581154432, 13589544832, 13597932928, 13606320512,
13614710656, 13623097472, 13631477632, 13639874944, 13648264064,
13656652928, 13665041792, 13673430656, 13681818496, 13690207616,
13698595712, 13706982272, 13715373184, 13723762048, 13732150144,
13740536704, 13748926592, 13757316224, 13765700992, 13774090112,
13782477952, 13790869376, 13799259008, 13807647872, 13816036736,
13824425344, 13832814208, 13841202304, 13849591424, 13857978752,
13866368896, 13874754688, 13883145344, 13891533184, 13899919232,
13908311168, 13916692096, 13925085056, 13933473152, 13941866368,
13950253696, 13958643584, 13967032192, 13975417216, 13983807616,
13992197504, 14000582272, 14008973696, 14017363072, 14025752192,
14034137984, 14042528384, 14050918016, 14059301504, 14067691648,
14076083584, 14084470144, 14092852352, 14101249664, 14109635968,
14118024832, 14126407552, 14134804352, 14143188608, 14151577984,
14159968384, 14168357248, 14176741504, 14185127296, 14193521024,
14201911424, 14210301824, 14218685056, 14227067264, 14235467392,
14243855488, 14252243072, 14260630144, 14269021568, 14277409408,
14285799296, 14294187904, 14302571392, 14310961792, 14319353728,
14327738752, 14336130944, 14344518784, 14352906368, 14361296512,
14369685376, 14378071424, 14386462592, 14394848128, 14403230848,
14411627392, 14420013952, 14428402304, 14436793472, 14445181568,
14453569664, 14461959808, 14470347904, 14478737024, 14487122816,
14495511424, 14503901824, 14512291712, 14520677504, 14529064832,
14537456768, 14545845632, 14554234496, 14562618496, 14571011456,
14579398784, 14587789184, 14596172672, 14604564608, 14612953984,
14621341312, 14629724288, 14638120832, 14646503296, 14654897536,
14663284864, 14671675264, 14680061056, 14688447616, 14696835968,
14705228416, 14713616768, 14722003328, 14730392192, 14738784128,
14747172736, 14755561088, 14763947648, 14772336512, 14780725376,
14789110144, 14797499776, 14805892736, 14814276992, 14822670208,
14831056256, 14839444352, 14847836032, 14856222848, 14864612992,
14872997504, 14881388672, 14889775744, 14898165376, 14906553472,
14914944896, 14923329664, 14931721856, 14940109696, 14948497024,
14956887424, 14965276544, 14973663616, 14982053248, 14990439808,
14998830976, 15007216768, 15015605888, 15023995264, 15032385152,
15040768384, 15049154944, 15057549184, 15065939072, 15074328448,
15082715008, 15091104128, 15099493504, 15107879296, 15116269184,
15124659584, 15133042304, 15141431936, 15149824384, 15158214272,
15166602368, 15174991232, 15183378304, 15191760512, 15200154496,
15208542592, 15216931712, 15225323392, 15233708416, 15242098048,
15250489216, 15258875264, 15267265408, 15275654528, 15284043136,
15292431488, 15300819584, 15309208192, 15317596544, 15325986176,
15334374784, 15342763648, 15351151744, 15359540608, 15367929728,
15376318336, 15384706432, 15393092992, 15401481856, 15409869952,
15418258816, 15426649984, 15435037568, 15443425664, 15451815296,
15460203392, 15468589184, 15476979328, 15485369216, 15493755776,
15502146944, 15510534272, 15518924416, 15527311232, 15535699072,
15544089472, 15552478336, 15560866688, 15569254528, 15577642624,
15586031488, 15594419072, 15602809472, 15611199104, 15619586432,
15627975296, 15636364928, 15644753792, 15653141888, 15661529216,
15669918848, 15678305152, 15686696576, 15695083136, 15703474048,
15711861632, 15720251264, 15728636288, 15737027456, 15745417088,
15753804928, 15762194048, 15770582656, 15778971008, 15787358336,
15795747712, 15804132224, 15812523392, 15820909696, 15829300096,
15837691264, 15846071936, 15854466944, 15862855808, 15871244672,
15879634816, 15888020608, 15896409728, 15904799104, 15913185152,
15921577088, 15929966464, 15938354816, 15946743424, 15955129472,
15963519872, 15971907968, 15980296064, 15988684928, 15997073024,
16005460864, 16013851264, 16022241152, 16030629248, 16039012736,
16047406976, 16055794816, 16064181376, 16072571264, 16080957824,
16089346688, 16097737856, 16106125184, 16114514816, 16122904192,
16131292544, 16139678848, 16148066944, 16156453504, 16164839552,
16173236096, 16181623424, 16190012032, 16198401152, 16206790528,
16215177344, 16223567744, 16231956352, 16240344704, 16248731008,
16257117824, 16265504384, 16273898624, 16282281856, 16290668672,
16299064192, 16307449216, 16315842176, 16324230016, 16332613504,
16341006464, 16349394304, 16357783168, 16366172288, 16374561664,
16382951296, 16391337856, 16399726208, 16408116352, 16416505472,
16424892032, 16433282176, 16441668224, 16450058624, 16458448768,
16466836864, 16475224448, 16483613056, 16492001408, 16500391808,
16508779648, 16517166976, 16525555328, 16533944192, 16542330752,
16550719616, 16559110528, 16567497088, 16575888512, 16584274816,
16592665472, 16601051008, 16609442944, 16617832064, 16626218624,
16634607488, 16642996096, 16651385728, 16659773824, 16668163712,
16676552576, 16684938112, 16693328768, 16701718144, 16710095488,
16718492288, 16726883968, 16735272832, 16743661184, 16752049792,
16760436608, 16768827008, 16777214336, 16785599104, 16793992832,
16802381696, 16810768768, 16819151744, 16827542656, 16835934848,
16844323712, 16852711552, 16861101952, 16869489536, 16877876864,
16886265728, 16894653056, 16903044736, 16911431296, 16919821696,
16928207488, 16936592768, 16944987776, 16953375616, 16961763968,
16970152832, 16978540928, 16986929536, 16995319168, 17003704448,
17012096896, 17020481152, 17028870784, 17037262208, 17045649536,
17054039936, 17062426496, 17070814336, 17079205504, 17087592064,
17095978112, 17104369024, 17112759424, 17121147776, 17129536384,
17137926016, 17146314368, 17154700928, 17163089792, 17171480192,
17179864192, 17188256896, 17196644992, 17205033856, 17213423488,
17221811072, 17230198912, 17238588032, 17246976896, 17255360384,
17263754624, 17272143232, 17280530048, 17288918912, 17297309312,
17305696384, 17314085504, 17322475136, 17330863744, 17339252096,
17347640192, 17356026496, 17364413824, 17372796544, 17381190016,
17389583488, 17397972608, 17406360704, 17414748544, 17423135872,
17431527296, 17439915904, 17448303232, 17456691584, 17465081728,
17473468288, 17481857408, 17490247552, 17498635904, 17507022464,
17515409024, 17523801728, 17532189824, 17540577664, 17548966016,
17557353344, 17565741184, 17574131584, 17582519168, 17590907008,
17599296128, 17607687808, 17616076672, 17624455808, 17632852352,
17641238656, 17649630848, 17658018944, 17666403968, 17674794112,
17683178368, 17691573376, 17699962496, 17708350592, 17716739968,
17725126528, 17733517184, 17741898112, 17750293888, 17758673024,
17767070336, 17775458432, 17783848832, 17792236928, 17800625536,
17809012352, 17817402752, 17825785984, 17834178944, 17842563968,
17850955648, 17859344512, 17867732864, 17876119424, 17884511872,
17892900224, 17901287296, 17909677696, 17918058112, 17926451072,
17934843776, 17943230848, 17951609216, 17960008576, 17968397696,
17976784256, 17985175424, 17993564032, 18001952128, 18010339712,
18018728576, 18027116672, 18035503232, 18043894144, 18052283264,
18060672128, 18069056384, 18077449856, 18085837184, 18094225792,
18102613376, 18111004544, 18119388544, 18127781248, 18136170368,
18144558976, 18152947328, 18161336192, 18169724288, 18178108544,
18186498944, 18194886784, 18203275648, 18211666048, 18220048768,
18228444544, 18236833408, 18245220736
];

View file

@ -7,184 +7,192 @@
var Keccak = require('./keccak');
var util = require('./util');
var ethUtil = require('ethereumjs-util');
// 32-bit unsigned modulo
function mod32(x, n)
{
return (x>>>0) % (n>>>0);
function mod32(x, n) {
return (x >>> 0) % (n >>> 0);
}
function fnv(x, y)
{
// js integer multiply by 0x01000193 will lose precision
return ((x*0x01000000 | 0) + (x*0x193 | 0)) ^ y;
function fnv(x, y) {
// js integer multiply by 0x01000193 will lose precision
return ((x * 0x01000000 | 0) + (x * 0x193 | 0)) ^ y;
}
function computeCache(params, seedWords)
{
var cache = new Uint32Array(params.cacheSize >> 2);
var cacheNodeCount = params.cacheSize >> 6;
function computeCache(params, seedWords) {
var cache = new Uint32Array(params.cacheSize >> 2);
var cacheNodeCount = params.cacheSize >> 6;
// Initialize cache
var keccak = new Keccak();
keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length);
for (var n = 1; n < cacheNodeCount; ++n)
{
keccak.digestWords(cache, n<<4, 16, cache, (n-1)<<4, 16);
}
var tmp = new Uint32Array(16);
// Do randmemohash passes
for (var r = 0; r < params.cacheRounds; ++r)
{
for (var n = 0; n < cacheNodeCount; ++n)
{
var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4;
var p1 = mod32(cache[n<<4|0], cacheNodeCount) << 4;
for (var w = 0; w < 16; w=(w+1)|0)
{
tmp[w] = cache[p0 | w] ^ cache[p1 | w];
}
keccak.digestWords(cache, n<<4, 16, tmp, 0, tmp.length);
}
}
return cache;
// Initialize cache
var keccak = new Keccak();
keccak.digestWords(cache, 0, 16, seedWords, 0, seedWords.length);
for (var n = 1; n < cacheNodeCount; ++n) {
keccak.digestWords(cache, n << 4, 16, cache, (n - 1) << 4, 16);
}
var tmp = new Uint32Array(16);
// Do randmemohash passes
for (var r = 0; r < params.cacheRounds; ++r) {
for (var n = 0; n < cacheNodeCount; ++n) {
var p0 = mod32(n + cacheNodeCount - 1, cacheNodeCount) << 4;
var p1 = mod32(cache[n << 4 | 0], cacheNodeCount) << 4;
for (var w = 0; w < 16; w = (w + 1) | 0) {
tmp[w] = cache[p0 | w] ^ cache[p1 | w];
}
keccak.digestWords(cache, n << 4, 16, tmp, 0, tmp.length);
}
}
return cache;
}
function computeDagNode(o_node, params, cache, keccak, nodeIndex)
{
var cacheNodeCount = params.cacheSize >> 6;
var dagParents = params.dagParents;
var c = (nodeIndex % cacheNodeCount) << 4;
var mix = o_node;
for (var w = 0; w < 16; ++w)
{
mix[w] = cache[c|w];
}
mix[0] ^= nodeIndex;
keccak.digestWords(mix, 0, 16, mix, 0, 16);
for (var p = 0; p < dagParents; ++p)
{
// compute cache node (word) index
c = mod32(fnv(nodeIndex ^ p, mix[p&15]), cacheNodeCount) << 4;
for (var w = 0; w < 16; ++w)
{
mix[w] = fnv(mix[w], cache[c|w]);
}
}
keccak.digestWords(mix, 0, 16, mix, 0, 16);
function computeDagNode(o_node, params, cache, keccak, nodeIndex) {
var cacheNodeCount = params.cacheSize >> 6;
var dagParents = params.dagParents;
var c = (nodeIndex % cacheNodeCount) << 4;
var mix = o_node;
for (var w = 0; w < 16; ++w) {
mix[w] = cache[c | w];
}
mix[0] ^= nodeIndex;
keccak.digestWords(mix, 0, 16, mix, 0, 16);
for (var p = 0; p < dagParents; ++p) {
// compute cache node (word) index
c = mod32(fnv(nodeIndex ^ p, mix[p & 15]), cacheNodeCount) << 4;
for (var w = 0; w < 16; ++w) {
mix[w] = fnv(mix[w], cache[c | w]);
}
}
keccak.digestWords(mix, 0, 16, mix, 0, 16);
}
function computeHashInner(mix, params, cache, keccak, tempNode)
{
var mixParents = params.mixParents|0;
var mixWordCount = params.mixSize >> 2;
var mixNodeCount = mixWordCount >> 4;
var dagPageCount = (params.dagSize / params.mixSize) >> 0;
// grab initial first word
var s0 = mix[0];
// initialise mix from initial 64 bytes
for (var w = 16; w < mixWordCount; ++w)
{
mix[w] = mix[w & 15];
}
for (var a = 0; a < mixParents; ++a)
{
var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount-1)]), dagPageCount);
var d = (p * mixNodeCount)|0;
for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16)
{
computeDagNode(tempNode, params, cache, keccak, (d + n)|0);
for (var v = 0; v < 16; ++v)
{
mix[w|v] = fnv(mix[w|v], tempNode[v]);
}
}
}
function computeHashInner(mix, params, cache, keccak, tempNode) {
var mixParents = params.mixParents | 0;
var mixWordCount = params.mixSize >> 2;
var mixNodeCount = mixWordCount >> 4;
var dagPageCount = (params.dagSize / params.mixSize) >> 0;
// grab initial first word
var s0 = mix[0];
// initialise mix from initial 64 bytes
for (var w = 16; w < mixWordCount; ++w) {
mix[w] = mix[w & 15];
}
for (var a = 0; a < mixParents; ++a) {
var p = mod32(fnv(s0 ^ a, mix[a & (mixWordCount - 1)]), dagPageCount);
var d = (p * mixNodeCount) | 0;
for (var n = 0, w = 0; n < mixNodeCount; ++n, w += 16) {
computeDagNode(tempNode, params, cache, keccak, (d + n) | 0);
for (var v = 0; v < 16; ++v) {
mix[w | v] = fnv(mix[w | v], tempNode[v]);
}
}
}
}
function convertSeed(seed)
{
// todo, reconcile with spec, byte ordering?
// todo, big-endian conversion
var newSeed = util.toWords(seed);
if (newSeed === null)
throw Error("Invalid seed '" + seed + "'");
return newSeed;
function convertSeed(seed) {
// todo, reconcile with spec, byte ordering?
// todo, big-endian conversion
var newSeed = util.toWords(seed);
if (newSeed === null)
throw Error("Invalid seed '" + seed + "'");
return newSeed;
}
exports.defaultParams = function()
{
return {
cacheSize: 1048384,
cacheRounds: 3,
dagSize: 1073739904,
dagParents: 256,
mixSize: 128,
mixParents: 64,
};
var params = exports.params = {
REVISION: 23,
DATASET_BYTES_INIT: 1073741824,
DATASET_BYTES_GROWTH: 8388608,
CACHE_BYTES_INIT: 1073741824,
CACHE_BYTES_GROWTH: 131072,
EPOCH_LENGTH: 30000,
MIX_BYTES: 128,
HASH_BYTES: 64,
DATASET_PARENTS: 256,
CACHE_ROUNDS: 3,
ACCESSES: 64
};
exports.Ethash = function(params, seed)
{
// precompute cache and related values
seed = convertSeed(seed);
var cache = computeCache(params, seed);
// preallocate buffers/etc
var initBuf = new ArrayBuffer(96);
var initBytes = new Uint8Array(initBuf);
var initWords = new Uint32Array(initBuf);
var mixWords = new Uint32Array(params.mixSize / 4);
var tempNode = new Uint32Array(16);
var keccak = new Keccak();
var retWords = new Uint32Array(8);
var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only
this.hash = function(header, nonce)
{
// compute initial hash
initBytes.set(header, 0);
initBytes.set(nonce, 32);
keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length/4);
// compute mix
for (var i = 0; i != 16; ++i)
{
mixWords[i] = initWords[i];
}
computeHashInner(mixWords, params, cache, keccak, tempNode);
// compress mix and append to initWords
for (var i = 0; i != mixWords.length; i += 4)
{
initWords[16 + i/4] = fnv(fnv(fnv(mixWords[i], mixWords[i+1]), mixWords[i+2]), mixWords[i+3]);
}
// final Keccak hashes
keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix)
return retBytes;
};
this.cacheDigest = function()
{
return keccak.digest(32, new Uint8Array(cache.buffer));
};
var cache_sizes = require('./cache_sizes');
var dag_sizes = require('./dag_sizes');
exports.calcSeed = function(blockNum) {
var epoch;
var seed = new Uint8Array(32);
if (blockNum > cache_sizes.length * params.EPOCH_LENGTH) {
return new Error('Time to upgrade to POS!!!');
} else {
epoch = Math.floor(blockNum / params.EPOCH_LENGTH);
for (var i = 0; i < epoch; i++) {
seed = ethUtil.sha3(new Buffer(seed));
}
return seed;
}
};
exports.defaultParams = function() {
return {
cacheSize: 1048384,
cacheRounds: 3,
dagSize: 1073739904,
dagParents: 256,
mixSize: 128,
mixParents: 64
};
};
exports.Ethash = function(params, seed) {
// precompute cache and related values
// seed = convertSeed(seed);
var cache = computeCache(params, seed);
// preallocate buffers/etc
var initBuf = new ArrayBuffer(96);
var initBytes = new Uint8Array(initBuf);
var initWords = new Uint32Array(initBuf);
var mixWords = new Uint32Array(params.mixSize / 4);
var tempNode = new Uint32Array(16);
var keccak = new Keccak();
var retWords = new Uint32Array(8);
var retBytes = new Uint8Array(retWords.buffer); // supposedly read-only
this.hash = function(header, nonce) {
// compute initial hash
initBytes.set(header, 0);
initBytes.set(nonce, 32);
keccak.digestWords(initWords, 0, 16, initWords, 0, 8 + nonce.length / 4);
// compute mix
for (var i = 0; i !== 16; ++i) {
mixWords[i] = initWords[i];
}
computeHashInner(mixWords, params, cache, keccak, tempNode);
// compress mix and append to initWords
for (var i = 0; i !== mixWords.length; i += 4) {
initWords[16 + i / 4] = fnv(fnv(fnv(mixWords[i], mixWords[i + 1]), mixWords[i + 2]), mixWords[i + 3]);
}
// final Keccak hashes
keccak.digestWords(retWords, 0, 8, initWords, 0, 24); // Keccak-256(s + cmix)
return retBytes;
};
this.cacheDigest = function() {
return keccak.digest(32, new Uint8Array(cache.buffer));
};
};

View file

@ -0,0 +1,21 @@
{
"name": "ethash.js",
"version": "0.0.1",
"description": "",
"main": "ethash.js",
"scripts": {
"test": "node ./test/test.js"
},
"repository": {
"type": "git",
"url": "https://github.com/ethereum/ethash/tree/master/js"
},
"keywords": [
"ethereum"
],
"author": "",
"license": "mit",
"devDependencies": {
"ethereum-tests": "0.0.5"
}
}

View file

@ -0,0 +1,48 @@
var tape = require('tape');
const ethash = require('../ethash.js');
tape('seed hash', function(t) {
t.test('seed should match TRUTH', function(st) {
const seed = '290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563';
const blockNum = 30000;
var r = new Buffer(ethash.calcSeed(blockNum));
st.equal(r.toString('hex'), seed);
st.end();
});
t.test('seed should match TRUTH2', function(st) {
const seed = '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9';
const blockNum = 60000;
var r = new Buffer(ethash.calcSeed(blockNum));
st.equal(r.toString('hex'), seed);
st.end();
});
t.test('seed should match TRUTH3', function(st) {
const seed = '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9';
const blockNum = 60700;
var r = new Buffer(ethash.calcSeed(blockNum));
st.equal(r.toString('hex'), seed);
st.end();
});
t.test('randomized tests', function(st) {
for (var i = 0; i < 100; i++) {
var x = Math.floor(ethash.params.EPOCH_LENGTH * 2048 * Math.random());
st.equal(ethash.calcSeed(x).toString('hex'), ethash.calcSeed(Math.floor(x / ethash.params.EPOCH_LENGTH) * ethash.params.EPOCH_LENGTH ).toString('hex'));
}
st.end();
});
// '510e4e770828ddbf7f7b00ab00a9f6adaf81c0dc9cc85f1f8249c256942d61d9'
// [7:13:32 PM] Matthew Wampler-Doty: >>> x = randint(0,700000)
//
// >>> pyethash.get_seedhash(x).encode('hex') == pyethash.get_seedhash((x // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH).encode('hex')
});

View file

@ -4,9 +4,9 @@
/*jslint node: true, shadow:true */
"use strict";
var ethash = require('./ethash');
var util = require('./util');
var Keccak = require('./keccak');
var ethash = require('../ethash');
var util = require('../util');
var Keccak = require('../keccak');
// sanity check hash functions
var src = util.stringToBytes("");
@ -31,23 +31,22 @@ var ethashParams = ethash.defaultParams();
var seed = util.hexStringToBytes("9410b944535a83d9adf6bbdcc80e051f30676173c16ca0d32d6f1263fc246466")
var startTime = new Date().getTime();
var hasher = new ethash.Ethash(ethashParams, seed);
console.log('Ethash startup took: '+(new Date().getTime() - startTime) + "ms");
console.log('Ethash startup took: ' + (new Date().getTime() - startTime) + "ms");
console.log('Ethash cache hash: ' + util.bytesToHexString(hasher.cacheDigest()));
var testHexString = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
if (testHexString != util.bytesToHexString(util.hexStringToBytes(testHexString)))
throw Error("bytesToHexString or hexStringToBytes broken");
throw Error("bytesToHexString or hexStringToBytes broken");
var header = util.hexStringToBytes("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
var nonce = util.hexStringToBytes("0000000000000000");
var hash;
startTime = new Date().getTime();
var trials = 10;
for (var i = 0; i < trials; ++i)
{
hash = hasher.hash(header, nonce);
for (var i = 0; i < trials; ++i) {
hash = hasher.hash(header, nonce);
}
console.log("Light client hashes averaged: " + (new Date().getTime() - startTime)/trials + "ms");
console.log("Light client hashes averaged: " + (new Date().getTime() - startTime) / trials + "ms");
console.log("Hash = " + util.bytesToHexString(hash));

View file

@ -1,2 +0,0 @@
pyethash.egg-info/
*.so

View file

@ -1,3 +0,0 @@
import pyethash.core
core = pyethash.core
EPOCH_LENGTH = 30000

View file

@ -1,21 +1,33 @@
#!/usr/bin/env python
from distutils.core import setup, Extension
pyethash_core = Extension('pyethash.core',
pyethash = Extension('pyethash',
sources = [
'src/python/core.c',
'src/libethash/util.c',
'src/libethash/internal.c',
'src/libethash/sha3.c'
'src/libethash/sha3.c'],
depends = [
'src/libethash/ethash.h',
'src/libethash/compiler.h',
'src/libethash/data_sizes.h',
'src/libethash/endian.h',
'src/libethash/ethash.h',
'src/libethash/fnv.h',
'src/libethash/internal.h',
'src/libethash/sha3.h',
'src/libethash/util.h'
],
extra_compile_args = ["-std=gnu99"])
extra_compile_args = ["-Isrc/", "-std=gnu99", "-Wall"])
setup (
name = 'pyethash',
author = "Matthew Wampler-Doty",
author_email = "matthew.wampler.doty@gmail.com",
license = 'GPL',
version = '1.0',
version = '23.1',
url = 'https://github.com/ethereum/ethash',
download_url = 'https://github.com/ethereum/ethash/tarball/v23.1',
description = 'Python wrappers for ethash, the ethereum proof of work hashing function',
ext_modules = [pyethash_core],
ext_modules = [pyethash],
)

View file

@ -31,7 +31,7 @@
#include <algorithm>
#ifdef WITH_CRYPTOPP
#include <libethash/SHA3_cryptopp.h>
#include <libethash/sha3_cryptopp.h>
#include <string>
#else

View file

@ -2,14 +2,39 @@ set(LIBRARY ethash-cl)
set(CMAKE_BUILD_TYPE Release)
include(bin2h.cmake)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl VARIABLE_NAME ethash_cl_miner_kernel HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
VARIABLE_NAME ethash_cl_miner_kernel
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
if (NOT MSVC)
# Initialize CXXFLAGS for c++11
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
# Compiler-specific C++11 activation.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
endif ()
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else ()
message(FATAL_ERROR "Your C++ compiler does not support C++11.")
endif ()
endif()
if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
include_directories(..)
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h)
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp)
TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash)
endif()

View file

@ -68,8 +68,7 @@ function(BIN2H)
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier
# TODO: fix for legacy cmake
IF (${CMAKE_VERSION} GREATER 2.8.10)
IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)

View file

@ -24,15 +24,22 @@
#include <assert.h>
#include <queue>
#include <vector>
#include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h"
#include <libethash/util.h>
#define ETHASH_BYTES 32
// workaround lame platforms
#if !CL_VERSION_1_2
#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE
#define CL_MEM_HOST_READ_ONLY 0
#endif
#undef min
#undef max
#define HASH_BYTES 32
static void add_definition(std::string& source, char const* id, unsigned value)
{
char buf[256];
@ -41,6 +48,7 @@ static void add_definition(std::string& source, char const* id, unsigned value)
}
ethash_cl_miner::ethash_cl_miner()
: m_opencl_1_1()
{
}
@ -71,11 +79,23 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
}
// use default device
cl::Device& device = devices[0];
debugf("Using device: %s\n", device.getInfo<CL_DEVICE_NAME>().c_str());
unsigned device_num = 0;
cl::Device& device = devices[device_num];
std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
debugf("Using device: %s (%s)\n", device.getInfo<CL_DEVICE_NAME>().c_str(),device_version.c_str());
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{
debugf("OpenCL 1.0 is not supported.\n");
return false;
}
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
{
m_opencl_1_1 = true;
}
// create context
m_context = cl::Context({device});
m_context = cl::Context(std::vector<cl::Device>(&device, &device+1));
m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8
@ -120,7 +140,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
ethash_mkcache(&cache, &params, seed);
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size);
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size);
ethash_compute_full_data(dag_ptr, &params, &cache);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
@ -130,7 +150,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
// create mining buffers
for (unsigned i = 0; i != c_num_buffers; ++i)
{
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, 32*c_hash_batch_size);
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size);
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
}
return true;
@ -176,7 +196,6 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce,
m_hash_kernel.setArg(0, m_hash_buf[buf]);
// execute it!
clock_t start_time = clock();
m_queue.enqueueNDRangeKernel(
m_hash_kernel,
cl::NullRange,
@ -196,8 +215,8 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce,
pending_batch const& batch = pending.front();
// could use pinned host pointer instead, but this path isn't that important.
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * HASH_BYTES);
memcpy(ret + batch.base*HASH_BYTES, hashes, batch.count*HASH_BYTES);
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES);
memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES);
m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes);
pending.pop();
@ -223,8 +242,19 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
{
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
}
#if CL_VERSION_1_2
cl::Event pre_return_event;
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else
#else
{
m_queue.finish();
}
#endif
/*
__kernel void ethash_combined_search(
@ -284,6 +314,11 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
}
// not safe to return until this is ready
pre_return_event.wait();
#if CL_VERSION_1_2
if (!m_opencl_1_1)
{
pre_return_event.wait();
}
#endif
}

View file

@ -40,4 +40,5 @@ private:
cl::Buffer m_hash_buf[c_num_buffers];
cl::Buffer m_search_buf[c_num_buffers];
unsigned m_workgroup_size;
bool m_opencl_1_1;
};

View file

@ -2,7 +2,6 @@ set(LIBRARY ethash)
if (CPPETHEREUM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
#else ()
endif ()
set(CMAKE_BUILD_TYPE Release)

View file

@ -20,8 +20,6 @@
* @date 2015
*/
// TODO: Update this after ~3.5 years
#pragma once
#include <stdint.h>
@ -33,23 +31,24 @@ extern "C" {
#include <stdint.h>
// 2048 Epochs worth of tabulated DAG sizes
// 2048 Epochs (~20 years) worth of tabulated DAG sizes
// Generated with the following Mathematica Code:
// GetDataSizes[n_] := Module[{
// DataSetSizeBytesInit = 2^30,
// MixBytes = 128,
// DataSetGrowth = 2^23,
// GetCacheSizes[n_] := Module[{
// CacheSizeBytesInit = 2^24,
// CacheGrowth = 2^17,
// HashBytes = 64,
// j = 0},
// Reap[
// While[j < n,
// Module[{i =
// Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / MixBytes]},
// While[! PrimeQ[i], i--];
// Sow[i*MixBytes]; j++]]]][[2]][[1]]
// Reap[
// While[j < n,
// Module[{i =
// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]},
// While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
static const size_t dag_sizes[] = {
static const uint64_t dag_sizes[2048] = {
1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U,
1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U,
1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U,
@ -478,300 +477,334 @@ static const size_t dag_sizes[] = {
// While[! PrimeQ[i], i--];
// Sow[i*HashBytes]; j++]]]][[2]][[1]]
const size_t cache_sizes[] = {
1048384U, 1055552U, 1064512U, 1072832U, 1080896U, 1089344U, 1096768U,
1104448U, 1113664U, 1121216U, 1130176U, 1138624U, 1146304U, 1155008U,
1162816U, 1171264U, 1179328U, 1187392U, 1195456U, 1203392U, 1210816U,
1220416U, 1227712U, 1236416U, 1244608U, 1253312U, 1261376U, 1268416U,
1277632U, 1285696U, 1294016U, 1302208U, 1310656U, 1318336U, 1326784U,
1334848U, 1342912U, 1350848U, 1359808U, 1366208U, 1376192U, 1383488U,
1392448U, 1400384U, 1408832U, 1416512U, 1425344U, 1433408U, 1440704U,
1449664U, 1458112U, 1466048U, 1474496U, 1482688U, 1490752U, 1498688U,
1507136U, 1515328U, 1523264U, 1531456U, 1539904U, 1547584U, 1556288U,
1564352U, 1572544U, 1580608U, 1588544U, 1596992U, 1605568U, 1612096U,
1621952U, 1630144U, 1637696U, 1645888U, 1654336U, 1662784U, 1671104U,
1679168U, 1686848U, 1695296U, 1702208U, 1711168U, 1720256U, 1727552U,
1736128U, 1744576U, 1751488U, 1760576U, 1769408U, 1777472U, 1785664U,
1793984U, 1801664U, 1810112U, 1818304U, 1826624U, 1834816U, 1842752U,
1851328U, 1858112U, 1867456U, 1875904U, 1883968U, 1892288U, 1899712U,
1908416U, 1916608U, 1924544U, 1932992U, 1940672U, 1948736U, 1956928U,
1965632U, 1973824U, 1982144U, 1989824U, 1998784U, 2006848U, 2014784U,
2022848U, 2031424U, 2038976U, 2047424U, 2055616U, 2064064U, 2072384U,
2080448U, 2088512U, 2095936U, 2104768U, 2113472U, 2121664U, 2127808U,
2137792U, 2146112U, 2153408U, 2162624U, 2170304U, 2178496U, 2186944U,
2195392U, 2203456U, 2211136U, 2219968U, 2227648U, 2236096U, 2244416U,
2250944U, 2260928U, 2268736U, 2276672U, 2283328U, 2293696U, 2301632U,
2309312U, 2317888U, 2325952U, 2334656U, 2342848U, 2350144U, 2358848U,
2366656U, 2375488U, 2383552U, 2391616U, 2400064U, 2407616U, 2415808U,
2424256U, 2432704U, 2439616U, 2448704U, 2457152U, 2464064U, 2473792U,
2482112U, 2489792U, 2497472U, 2506432U, 2514752U, 2522816U, 2531264U,
2539456U, 2547136U, 2555456U, 2564032U, 2572096U, 2578496U, 2587712U,
2595776U, 2604736U, 2613056U, 2620736U, 2629184U, 2637632U, 2645824U,
2653888U, 2662208U, 2670016U, 2678464U, 2686912U, 2694464U, 2703296U,
2710976U, 2719424U, 2727104U, 2736064U, 2743232U, 2752192U, 2760512U,
2768704U, 2777024U, 2785088U, 2792512U, 2800576U, 2809024U, 2817856U,
2826176U, 2833984U, 2840896U, 2850752U, 2858048U, 2867008U, 2875328U,
2883392U, 2891584U, 2899648U, 2908096U, 2915648U, 2924224U, 2932672U,
2940736U, 2948672U, 2956736U, 2964928U, 2973248U, 2981824U, 2988992U,
2997184U, 3005248U, 3013952U, 3022144U, 3030592U, 3037376U, 3046976U,
3055552U, 3063616U, 3070784U, 3079744U, 3087808U, 3096512U, 3103808U,
3111872U, 3121088U, 3128896U, 3137216U, 3144896U, 3153856U, 3161152U,
3169984U, 3178432U, 3186496U, 3194816U, 3203008U, 3210176U, 3218624U,
3227072U, 3235264U, 3243712U, 3250496U, 3259456U, 3268544U, 3276736U,
3283648U, 3292736U, 3301184U, 3308224U, 3317696U, 3324736U, 3333184U,
3342272U, 3348544U, 3357248U, 3365312U, 3374912U, 3383104U, 3390784U,
3399488U, 3407296U, 3414976U, 3424192U, 3432256U, 3440576U, 3448768U,
3456832U, 3464896U, 3473216U, 3480128U, 3489344U, 3497408U, 3505856U,
3514048U, 3521344U, 3530432U, 3538624U, 3546304U, 3555008U, 3563072U,
3571648U, 3579712U, 3587392U, 3595456U, 3603904U, 3612352U, 3620416U,
3628864U, 3636928U, 3645248U, 3652928U, 3660992U, 3669184U, 3677888U,
3685952U, 3694528U, 3702592U, 3710528U, 3719104U, 3727168U, 3735488U,
3742784U, 3751232U, 3759424U, 3765184U, 3775808U, 3783872U, 3792832U,
3800768U, 3808832U, 3816256U, 3825344U, 3832768U, 3841856U, 3849536U,
3857344U, 3866432U, 3874496U, 3882304U, 3890752U, 3899072U, 3907264U,
3914816U, 3923008U, 3930688U, 3939904U, 3947968U, 3956416U, 3964736U,
3972544U, 3981248U, 3988928U, 3997376U, 4005824U, 4012864U, 4020928U,
4030144U, 4038592U, 4045504U, 4054592U, 4063168U, 4071104U, 4079552U,
4087232U, 4095808U, 4103872U, 4111168U, 4120384U, 4127936U, 4136512U,
4144832U, 4153024U, 4160704U, 4169408U, 4177216U, 4186048U, 4193344U,
4202048U, 4210496U, 4217536U, 4227008U, 4235072U, 4243264U, 4251584U,
4259392U, 4267712U, 4275776U, 4284352U, 4291904U, 4300096U, 4307648U,
4316992U, 4325056U, 4333376U, 4341056U, 4349888U, 4357568U, 4366016U,
4374464U, 4382528U, 4390208U, 4398656U, 4407232U, 4413632U, 4423616U,
4431808U, 4439744U, 4447936U, 4455872U, 4463296U, 4472128U, 4480576U,
4489024U, 4497344U, 4505152U, 4512448U, 4520896U, 4530112U, 4537664U,
4546496U, 4554688U, 4562752U, 4570816U, 4579264U, 4586944U, 4595648U,
4603712U, 4611392U, 4619072U, 4628032U, 4635584U, 4643776U, 4652864U,
4660672U, 4669376U, 4677056U, 4684096U, 4693184U, 4702144U, 4710208U,
4718528U, 4726336U, 4734272U, 4742464U, 4750784U, 4759232U, 4767296U,
4775872U, 4783808U, 4791872U, 4797376U, 4808512U, 4816192U, 4825024U,
4832704U, 4841024U, 4849472U, 4856512U, 4865984U, 4874176U, 4882112U,
4889792U, 4898752U, 4906688U, 4913984U, 4922816U, 4931008U, 4938944U,
4946624U, 4955584U, 4964032U, 4972096U, 4980032U, 4988864U, 4997056U,
5004992U, 5012288U, 5020096U, 5029312U, 5037632U, 5045696U, 5052224U,
5062592U, 5070784U, 5078848U, 5086784U, 5095232U, 5100736U, 5111488U,
5119936U, 5127104U, 5136064U, 5143616U, 5151424U, 5160256U, 5168704U,
5175232U, 5185472U, 5192384U, 5199296U, 5209664U, 5218112U, 5225536U,
5233472U, 5242816U, 5250496U, 5258944U, 5267264U, 5274944U, 5283776U,
5290048U, 5300032U, 5308096U, 5316544U, 5323328U, 5331904U, 5340736U,
5349056U, 5356864U, 5365312U, 5372096U, 5381696U, 5390272U, 5398336U,
5405888U, 5413696U, 5422784U, 5430976U, 5439424U, 5446976U, 5455808U,
5463616U, 5471168U, 5480128U, 5488064U, 5494592U, 5504704U, 5513152U,
5521216U, 5529536U, 5536576U, 5544256U, 5554112U, 5559616U, 5570368U,
5577664U, 5586752U, 5594944U, 5603008U, 5611456U, 5619392U, 5627584U,
5634368U, 5643328U, 5651264U, 5659328U, 5667008U, 5675584U, 5684416U,
5692864U, 5701568U, 5709632U, 5717056U, 5725376U, 5734336U, 5740096U,
5750336U, 5758912U, 5766848U, 5775296U, 5782976U, 5790784U, 5799616U,
5807936U, 5815232U, 5823808U, 5832256U, 5840192U, 5848768U, 5856832U,
5864896U, 5873344U, 5879872U, 5888576U, 5897792U, 5905216U, 5914432U,
5920448U, 5930944U, 5938624U, 5947328U, 5955392U, 5963456U, 5971648U,
5979328U, 5988032U, 5995712U, 6003904U, 6012736U, 6021056U, 6029248U,
6037184U, 6045632U, 6053312U, 6061376U, 6070208U, 6077504U, 6086464U,
6094784U, 6101696U, 6110912U, 6118592U, 6127168U, 6135616U, 6143296U,
6150208U, 6158912U, 6168128U, 6175808U, 6182464U, 6192832U, 6201152U,
6209344U, 6217664U, 6224576U, 6233408U, 6241472U, 6249664U, 6258496U,
6266816U, 6275008U, 6281152U, 6291136U, 6299456U, 6306752U, 6314816U,
6323776U, 6332096U, 6339392U, 6348224U, 6356288U, 6364096U, 6373184U,
6381376U, 6389696U, 6397504U, 6404416U, 6413632U, 6421952U, 6430016U,
6437824U, 6446912U, 6454592U, 6463168U, 6471616U, 6478144U, 6487232U,
6496192U, 6504128U, 6511936U, 6520256U, 6528832U, 6536896U, 6544576U,
6553408U, 6561472U, 6569792U, 6577216U, 6586304U, 6592448U, 6601024U,
6610624U, 6619072U, 6627136U, 6634816U, 6643264U, 6650816U, 6659776U,
6667712U, 6675904U, 6682688U, 6691904U, 6700864U, 6709184U, 6717376U,
6724544U, 6733504U, 6741824U, 6749888U, 6756032U, 6766528U, 6773056U,
6782912U, 6790976U, 6798016U, 6807488U, 6815168U, 6823744U, 6832064U,
6840128U, 6847552U, 6855872U, 6864064U, 6872128U, 6880576U, 6889408U,
6897472U, 6905792U, 6913472U, 6920896U, 6930368U, 6938432U, 6946624U,
6953536U, 6963136U, 6971072U, 6979136U, 6986944U, 6995392U, 7003712U,
7012288U, 7019072U, 7028416U, 7036352U, 7044416U, 7051712U, 7060672U,
7069376U, 7077568U, 7085504U, 7092544U, 7102016U, 7110592U, 7118656U,
7126208U, 7135168U, 7143104U, 7150912U, 7159744U, 7167808U, 7175744U,
7184192U, 7191232U, 7200448U, 7207744U, 7216576U, 7224128U, 7233472U,
7241536U, 7249856U, 7256512U, 7264832U, 7274048U, 7282112U, 7290176U,
7298752U, 7306688U, 7315136U, 7322816U, 7331392U, 7339456U, 7347776U,
7356224U, 7364288U, 7371712U, 7380928U, 7387456U, 7396544U, 7404352U,
7413568U, 7421632U, 7429696U, 7436864U, 7446464U, 7454144U, 7461952U,
7470784U, 7478336U, 7487296U, 7495616U, 7503424U, 7511872U, 7520192U,
7527616U, 7536448U, 7544512U, 7551424U, 7560128U, 7568576U, 7577536U,
7583552U, 7592512U, 7600448U, 7610048U, 7618496U, 7626176U, 7634752U,
7642816U, 7651264U, 7659328U, 7667008U, 7675456U, 7683136U, 7691584U,
7700416U, 7707584U, 7716416U, 7724224U, 7733056U, 7740608U, 7749184U,
7756096U, 7765952U, 7774016U, 7781824U, 7790528U, 7798592U, 7805888U,
7814336U, 7822784U, 7831232U, 7839296U, 7847104U, 7855552U, 7863616U,
7872448U, 7880128U, 7888576U, 7896256U, 7905088U, 7912768U, 7920448U,
7928768U, 7937344U, 7945792U, 7953728U, 7959488U, 7970752U, 7978816U,
7987136U, 7994816U, 8003392U, 8011712U, 8019904U, 8027456U, 8035264U,
8044352U, 8052544U, 8060224U, 8069056U, 8076736U, 8084672U, 8093504U,
8101312U, 8110016U, 8117696U, 8125888U, 8134592U, 8142016U, 8149952U,
8159168U, 8166976U, 8175296U, 8183488U, 8191808U, 8199616U, 8207296U,
8216128U, 8224576U, 8232256U, 8241088U, 8248256U, 8257472U, 8264128U,
8273728U, 8281792U, 8290112U, 8297152U, 8305216U, 8314816U, 8322752U,
8330944U, 8339392U, 8347072U, 8355392U, 8363968U, 8371904U, 8379328U,
8388544U, 8394944U, 8404544U, 8412736U, 8421184U, 8429504U, 8437696U,
8445376U, 8452544U, 8460736U, 8470208U, 8478016U, 8486848U, 8494144U,
8503232U, 8511296U, 8519488U, 8527424U, 8534464U, 8543936U, 8552384U,
8558912U, 8568128U, 8575936U, 8584256U, 8593216U, 8601536U, 8608832U,
8616896U, 8625728U, 8634176U, 8641856U, 8649664U, 8658112U, 8666176U,
8674112U, 8682944U, 8691136U, 8699456U, 8707648U, 8716096U, 8724416U,
8732608U, 8740672U, 8748352U, 8756032U, 8764864U, 8773568U, 8781376U,
8789824U, 8796992U, 8806208U, 8814272U, 8822336U, 8830912U, 8838848U,
8847296U, 8854336U, 8863552U, 8871488U, 8879296U, 8887616U, 8894528U,
8904512U, 8911424U, 8920768U, 8928704U, 8936128U, 8944576U, 8953664U,
8960576U, 8970176U, 8977984U, 8986304U, 8994112U, 9002432U, 9011008U,
9018176U, 9026624U, 9035584U, 9043904U, 9052096U, 9059264U, 9068096U,
9075904U, 9084224U, 9092288U, 9100352U, 9108928U, 9116992U, 9125824U,
9133504U, 9141824U, 9150272U, 9157952U, 9164608U, 9174848U, 9182912U,
9190976U, 9199552U, 9205312U, 9215936U, 9222592U, 9232192U, 9240512U,
9248704U, 9256256U, 9264832U, 9272896U, 9281344U, 9288896U, 9297088U,
9305536U, 9313984U, 9322304U, 9329728U, 9337792U, 9346112U, 9355072U,
9363136U, 9371072U, 9378752U, 9387712U, 9395648U, 9404224U, 9411008U,
9420608U, 9428416U, 9436864U, 9445312U, 9453376U, 9460928U, 9468736U,
9477824U, 9485248U, 9493696U, 9502144U, 9509056U, 9518528U, 9527104U,
9535424U, 9543616U, 9551296U, 9559744U, 9568192U, 9576256U, 9584576U,
9591872U, 9600704U, 9608384U, 9615808U, 9624512U, 9633472U, 9641536U,
9649856U, 9658048U, 9665728U, 9674432U, 9682496U, 9691072U, 9699136U,
9707072U, 9715136U, 9722176U, 9732032U, 9740096U, 9747904U, 9756352U,
9764288U, 9771584U, 9780544U, 9789376U, 9796928U, 9804224U, 9813952U,
9822016U, 9829696U, 9838016U, 9845824U, 9852992U, 9863104U, 9870656U,
9878464U, 9887552U, 9895744U, 9903808U, 9912128U, 9920192U, 9927616U,
9936064U, 9944768U, 9952576U, 9960128U, 9969472U, 9977152U, 9985216U,
9994048U, 10001216U, 10007744U, 10018496U, 10026944U, 10035136U, 10042432U,
10051264U, 10059584U, 10067648U, 10075712U, 10083904U, 10091456U, 10100672U,
10108864U, 10116928U, 10124864U, 10133056U, 10140736U, 10149824U, 10156736U,
10165952U, 10173376U, 10182208U, 10190528U, 10198336U, 10206272U, 10213696U,
10223296U, 10231744U, 10238656U, 10247488U, 10256192U, 10263872U, 10272448U,
10280896U, 10288448U, 10296512U, 10305088U, 10313536U, 10321088U, 10330048U,
10337984U, 10346176U, 10354112U, 10362304U, 10369088U, 10377152U, 10386752U,
10394816U, 10403648U, 10411712U, 10418624U, 10427968U, 10436032U, 10444736U,
10452928U, 10459712U, 10468672U, 10476608U, 10484416U, 10491328U, 10501952U,
10509376U, 10517824U, 10526528U, 10534336U, 10542656U, 10549696U, 10559168U,
10566592U, 10575808U, 10583488U, 10590656U, 10599488U, 10607936U, 10616768U,
10624832U, 10630336U, 10640576U, 10649536U, 10655168U, 10665152U, 10674112U,
10682176U, 10690496U, 10698176U, 10705216U, 10715072U, 10722752U, 10731328U,
10739264U, 10746688U, 10754752U, 10761664U, 10770752U, 10779712U, 10787776U,
10796608U, 10803392U, 10812352U, 10821056U, 10828736U, 10837952U, 10846144U,
10853824U, 10861376U, 10869952U, 10877248U, 10887104U, 10895296U, 10903232U,
10910912U, 10918976U, 10927936U, 10935872U, 10944448U, 10952384U, 10960832U,
10968512U, 10977088U, 10985024U, 10992832U, 11000896U, 11009984U, 11018048U,
11026112U, 11034304U, 11042624U, 11050432U, 11058368U, 11064512U, 11075392U,
11083712U, 11091776U, 11099584U, 11107904U, 11115968U, 11124416U, 11131712U,
11141056U, 11148608U, 11157184U, 11165248U, 11173312U, 11180992U, 11189056U,
11197376U, 11206592U, 11214656U, 11222336U, 11230784U, 11238464U, 11246528U,
11254976U, 11263552U, 11271872U, 11279552U, 11288512U, 11296576U, 11304256U,
11312192U, 11320768U, 11329216U, 11336384U, 11345216U, 11352512U, 11362112U,
11369408U, 11378624U, 11386688U, 11394496U, 11402816U, 11411264U, 11418688U,
11427776U, 11435584U, 11444032U, 11452096U, 11459648U, 11467072U, 11476928U,
11484992U, 11493184U, 11500352U, 11509312U, 11517248U, 11524928U, 11534144U,
11542208U, 11550272U, 11556416U, 11566784U, 11574208U, 11581376U, 11589568U,
11599552U, 11607104U, 11616064U, 11623616U, 11632576U, 11639872U, 11648704U,
11657024U, 11664704U, 11672896U, 11681216U, 11689792U, 11697856U, 11705536U,
11714368U, 11722688U, 11730496U, 11737408U, 11745728U, 11754304U, 11763008U,
11770816U, 11779648U, 11788096U, 11795776U, 11804608U, 11812544U, 11820992U,
11829184U, 11837248U, 11844928U, 11852096U, 11860928U, 11869888U, 11878336U,
11886272U, 11894336U, 11902144U, 11910848U, 11919296U, 11925952U, 11934784U,
11943616U, 11951552U, 11960128U, 11968192U, 11976512U, 11983168U, 11992768U,
12000832U, 12008896U, 12016832U, 12025408U, 12033856U, 12042176U, 12049984U,
12058048U, 12066112U, 12073792U, 12082624U, 12091328U, 12098752U, 12106816U,
12115904U, 12124096U, 12131776U, 12140224U, 12148672U, 12156736U, 12164032U,
12173248U, 12181184U, 12186176U, 12197824U, 12205888U, 12213952U, 12218944U,
12230336U, 12238784U, 12246592U, 12254272U, 12262336U, 12269888U, 12279104U,
12287936U, 12295744U, 12304064U, 12312512U, 12319936U, 12328768U, 12337088U,
12344896U, 12352832U, 12361408U, 12368704U, 12377152U, 12384832U, 12394432U,
12402496U, 12409024U, 12417728U, 12426688U, 12433216U, 12443584U, 12450752U,
12459968U, 12468032U, 12475712U, 12484544U, 12492608U, 12500416U, 12508352U,
12517184U, 12525376U, 12532288U, 12541888U, 12549568U, 12556864U, 12565568U,
12574528U, 12582208U, 12590528U, 12598592U, 12607424U, 12615488U, 12623552U,
12631744U, 12638656U, 12647744U, 12656576U, 12664768U, 12672832U, 12680896U,
12688576U, 12697408U, 12704192U, 12713408U, 12721216U, 12729664U, 12738496U,
12745792U, 12754496U, 12762688U, 12769472U, 12779456U, 12787648U, 12795712U,
12804032U, 12812224U, 12819008U, 12828352U, 12836672U, 12844736U, 12851648U,
12859456U, 12868672U, 12877504U, 12885568U, 12892864U, 12902336U, 12909376U,
12918208U, 12926656U, 12934976U, 12942784U, 12951104U, 12959552U, 12967744U,
12976064U, 12984256U, 12991936U, 12999488U, 13007936U, 13016768U, 13021504U,
13033024U, 13041472U, 13049408U, 13057472U, 13065664U, 13072064U, 13081408U,
13089344U, 13098688U, 13107008U, 13115072U, 13122752U, 13130944U, 13139648U,
13147712U, 13155776U, 13162432U, 13172672U, 13180864U, 13188928U, 13196992U,
13203392U, 13213504U, 13219264U, 13228736U, 13236928U, 13244992U, 13253056U,
13262528U, 13269952U, 13278784U, 13285952U, 13295552U, 13303616U, 13311808U,
13319744U, 13328192U, 13336256U, 13344704U, 13352384U, 13360576U, 13369024U,
13377344U, 13385408U, 13393216U, 13401664U, 13410112U, 13418176U, 13426496U,
13434688U, 13442368U, 13451072U, 13459136U, 13466944U, 13475648U, 13482944U,
13491904U, 13500352U, 13508288U, 13516736U, 13524416U, 13532224U, 13541312U,
13549504U, 13556288U, 13564736U, 13573184U, 13581376U, 13587008U, 13598656U,
13605952U, 13612864U, 13622464U, 13631168U, 13639616U, 13647808U, 13655104U,
13663424U, 13671872U, 13680064U, 13688768U, 13696576U, 13705024U, 13712576U,
13721536U, 13729216U, 13737664U, 13746112U, 13753024U, 13759552U, 13770304U,
13777856U, 13786688U, 13793984U, 13802176U, 13811264U, 13819328U, 13827904U,
13835456U, 13844416U, 13851584U, 13860544U, 13868992U, 13877056U, 13884608U,
13893184U, 13901248U, 13909696U, 13917632U, 13925056U, 13934528U, 13942336U,
13950784U, 13959104U, 13966912U, 13975232U, 13982656U, 13991872U, 13999936U,
14007872U, 14016064U, 14024512U, 14032064U, 14040896U, 14049088U, 14057408U,
14065088U, 14072896U, 14081344U, 14089664U, 14097856U, 14106304U, 14114752U,
14122688U, 14130752U, 14138816U, 14147008U, 14155072U, 14163904U, 14170432U,
14180288U, 14187328U, 14196032U, 14204864U, 14212672U, 14220736U, 14229056U,
14237504U, 14245568U, 14253632U, 14261824U, 14269888U, 14278592U, 14286656U,
14293696U, 14302784U, 14309696U, 14317504U, 14326336U, 14335936U, 14343232U,
14352064U, 14359232U, 14368064U, 14376512U, 14384576U, 14393024U, 14401472U,
14409536U, 14416832U, 14424512U, 14433856U, 14440768U, 14449984U, 14458816U,
14465728U, 14474816U, 14482112U, 14491328U, 14499392U, 14506816U, 14516032U,
14524352U, 14531392U, 14540224U, 14547392U, 14556992U, 14565184U, 14573248U,
14580928U, 14588864U, 14596928U, 14606272U, 14613824U, 14622656U, 14630464U,
14638912U, 14646976U, 14655296U, 14661952U, 14671808U, 14679872U, 14687936U,
14696384U, 14704576U, 14710336U, 14720192U, 14729152U, 14736448U, 14745152U,
14752448U, 14761792U, 14769856U, 14777024U, 14785984U, 14792384U, 14802752U,
14810816U, 14819264U, 14827328U, 14835136U, 14843072U, 14851264U, 14860096U,
14867648U, 14876096U, 14884544U, 14892736U, 14900672U, 14907968U, 14917312U,
14924864U, 14933824U, 14939968U, 14950336U, 14957632U, 14966464U, 14974912U,
14982592U, 14991296U, 14999104U, 15006272U, 15015232U, 15023936U, 15031616U,
15040448U, 15047488U, 15055552U, 15063616U, 15073216U, 15079744U, 15088064U,
15097664U, 15105344U, 15113792U, 15122368U, 15130048U, 15137728U, 15146176U,
15154112U, 15162688U, 15171392U, 15179456U, 15187264U, 15194176U, 15204032U,
15212224U, 15220544U, 15227456U, 15237056U, 15245248U, 15253184U, 15261632U,
15269824U, 15277376U, 15285824U, 15293888U, 15301568U, 15310784U, 15318848U,
15325504U, 15335104U, 15343168U, 15350848U, 15359936U, 15367232U, 15373376U,
15384256U, 15392576U, 15400384U, 15408832U, 15417152U, 15424832U, 15433024U,
15441344U, 15449152U, 15457088U, 15466432U, 15474112U, 15482816U, 15488576U,
15499072U, 15505856U, 15514816U, 15523264U, 15531584U, 15540032U, 15547328U,
15553984U, 15564608U, 15571904U, 15579968U, 15589312U, 15597376U, 15605696U,
15612992U, 15621824U, 15630016U, 15638464U, 15646144U, 15654592U, 15662912U,
15671104U, 15677248U, 15686848U, 15693376U, 15701696U, 15712064U, 15720256U,
15728576U, 15736384U, 15744704U, 15752512U, 15761344U, 15769024U, 15777728U,
15785152U, 15793984U, 15802048U, 15809984U, 15817024U, 15825856U, 15834944U,
15843008U, 15849664U, 15859136U, 15866432U, 15876032U, 15884096U, 15892288U,
15900608U, 15908416U, 15916864U, 15924928U, 15930176U, 15941056U, 15949504U,
15957824U, 15965632U, 15973952U, 15982528U, 15990592U, 15998272U, 16006976U,
16012736U, 16023104U, 16031296U, 16039616U, 16048064U, 16055744U, 16064192U,
16071488U, 16080832U, 16088768U, 16097216U, 16104896U, 16112704U, 16121792U,
16129856U, 16138048U, 16146112U, 16154176U, 16162624U, 16170688U, 16177856U,
16186816U, 16195136U, 16202176U, 16211648U, 16220096U, 16228288U, 16235584U,
16244672U, 16252864U, 16260544U, 16269248U, 16277056U, 16285504U, 16291648U,
16301632U, 16309312U, 16318144U, 16326208U, 16333888U, 16342336U, 16351168U,
16359232U, 16367552U, 16375616U, 16383296U, 16391744U, 16398016U, 16407616U,
16415936U, 16424896U, 16432448U, 16440896U, 16449088U, 16457024U, 16465472U,
16474048U, 16481216U, 16490048U, 16498624U, 16505792U, 16513984U, 16523072U,
16531136U, 16538944U, 16547264U, 16555328U, 16563776U, 16570816U, 16578112U,
16587712U, 16596544U, 16604992U, 16613312U, 16620608U, 16629568U, 16637888U,
16645696U, 16653632U, 16661696U, 16669888U, 16677568U, 16686272U, 16695232U,
16703168U, 16710464U, 16719424U, 16726592U, 16733888U, 16744384U, 16752448U,
16760768U, 16768448U, 16776896U, 16785344U, 16793536U, 16801216U, 16809664U,
16818112U, 16826176U, 16833472U, 16842688U, 16850752U, 16859072U, 16866368U,
16875328U, 16883392U, 16891712U, 16899776U, 16907456U, 16915264U, 16924352U,
16931776U, 16940608U, 16949056U, 16957376U, 16965056U, 16973248U, 16981696U,
16990144U, 16997056U, 17005888U, 17014208U, 17021504U, 17031104U, 17039296U,
17046976U, 17055424U, 17062592U, 17070016U, 17079488U, 17087936U, 17096512U,
17104576U, 17113024U, 17121088U, 17129408U, 17136832U, 17145664U, 17152832U,
17161792U, 17170112U, 17177792U, 17186368U, 17194304U, 17202496U, 17211328U,
17218624U, 17227712U, 17233984U, 17243584U, 17251904U, 17259712U, 17266624U,
17276608U, 17284672U, 17292224U, 17301056U, 17309632U, 17317568U, 17326016U,
17333824U, 17342272U, 17350208U, 17358784U, 17366848U, 17374912U, 17382592U,
17390656U, 17399488U, 17406784U, 17413952U, 17423936U, 17432512U, 17440448U,
17447744U, 17456704U, 17464768U, 17472064U, 17481536U, 17489344U, 17495488U,
17505728U, 17513792U, 17522368U, 17530816U, 17538112U, 17546944U, 17555264U,
17563072U, 17569856U, 17579456U, 17587904U, 17596352U, 17603776U, 17611712U,
17620672U, 17628992U, 17637184U, 17645504U, 17653568U, 17661632U, 17669824U,
17677376U, 17686208U, 17693888U, 17702336U, 17710144U, 17718208U, 17726528U,
17734336U, 17743808U, 17751872U, 17759936U, 17766592U, 17776448U, 17784512U,
17791936U, 17801152U, 17809216U, 17817152U
const uint64_t cache_sizes[2048] = {
16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U,
17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U,
18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U,
19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U,
20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U,
21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U,
22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U,
23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U,
24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U,
25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U,
25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U,
26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U,
27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U,
28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U,
29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U,
30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U,
31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U,
32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U,
33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U,
34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U,
35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U,
36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U,
36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U,
37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U,
38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U,
39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U,
40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U,
41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U,
42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U,
43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U,
44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U,
45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U,
46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U,
47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U,
47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U,
48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U,
49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U,
50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U,
51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U,
52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U,
53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U,
54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U,
55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U,
56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U,
57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U,
58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U,
58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U,
59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U,
60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U,
61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U,
62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U,
63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U,
64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U,
65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U,
66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U,
67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U,
68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U,
69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U,
69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U,
70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U,
71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U,
72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U,
73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U,
74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U,
75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U,
76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U,
77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U,
78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U,
79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U,
80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U,
81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U,
81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U,
82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U,
83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U,
84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U,
85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U,
86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U,
87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U,
88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U,
89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U,
90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U,
91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U,
92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U,
92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U,
93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U,
94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U,
95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U,
96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U,
97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U,
98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U,
99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U,
100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U,
100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U,
101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U,
102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U,
103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U,
104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U,
104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U,
105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U,
106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U,
107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U,
108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U,
108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U,
109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U,
110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U,
111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U,
111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U,
112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U,
113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U,
114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U,
115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U,
115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U,
116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U,
117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U,
118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U,
119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U,
119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U,
120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U,
121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U,
122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U,
122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U,
123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U,
124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U,
125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U,
126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U,
126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U,
127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U,
128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U,
129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U,
130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U,
130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U,
131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U,
132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U,
133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U,
133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U,
134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U,
135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U,
136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U,
137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U,
137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U,
138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U,
139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U,
140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U,
141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U,
141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U,
142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U,
143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U,
144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U,
144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U,
145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U,
146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U,
147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U,
148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U,
148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U,
149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U,
150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U,
151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U,
152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U,
152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U,
153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U,
154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U,
155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U,
155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U,
156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U,
157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U,
158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U,
159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U,
159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U,
160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U,
161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U,
162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U,
163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U,
163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U,
164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U,
165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U,
166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U,
166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U,
167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U,
168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U,
169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U,
170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U,
170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U,
171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U,
172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U,
173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U,
174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U,
174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U,
175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U,
176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U,
177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U,
177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U,
178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U,
179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U,
180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U,
181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U,
181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U,
182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U,
183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U,
184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U,
185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U,
185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U,
186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U,
187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U,
188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U,
189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U,
189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U,
190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U,
191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U,
192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U,
192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U,
193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U,
194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U,
195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U,
196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U,
196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U,
197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U,
198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U,
199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U,
200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U,
200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U,
201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U,
202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U,
203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U,
203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U,
204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U,
205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U,
206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U,
207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U,
207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U,
208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U,
209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U,
210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U,
211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U,
211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U,
212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U,
213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U,
214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U,
214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U,
215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U,
216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U,
217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U,
218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U,
218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U,
219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U,
220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U,
221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U,
222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U,
222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U,
223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U,
224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U,
225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U,
225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U,
226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U,
227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U,
228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U,
229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U,
229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U,
230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U,
231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U,
232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U,
233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U,
233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U,
234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U,
235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U,
236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U,
236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U,
237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U,
238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U,
239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U,
240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U,
240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U,
241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U,
242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U,
243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U,
244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U,
244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U,
245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U,
246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U,
247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U,
247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U,
248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U,
249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U,
250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U,
251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U,
251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U,
252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U,
253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U,
254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U,
255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U,
255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U,
256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U,
257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U,
258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U,
258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U,
259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U,
260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U,
261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U,
262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U,
262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U,
263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U,
264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U,
265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U,
266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U,
266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U,
267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U,
268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U,
269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U,
270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U,
270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U,
271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U,
272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U,
273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U,
273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U,
274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U,
275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U,
276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U,
277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U,
277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U,
278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U,
279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U,
280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U,
281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U,
281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U,
282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U,
283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U,
284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U,
284950208U, 285081536U
};
#ifdef __cplusplus

View file

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify
ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash.h
@ -26,13 +26,15 @@
#include <stddef.h>
#include "compiler.h"
#define REVISION 20
#define DAGSIZE_BYTES_INIT 1073741824U // 2**30
#define DAG_GROWTH 8388608U // 2**23
#define CACHE_MULTIPLIER 1024
#define REVISION 23
#define DATASET_BYTES_INIT 1073741824U // 2**30
#define DATASET_BYTES_GROWTH 8388608U // 2**23
#define CACHE_BYTES_INIT 1073741824U // 2**24
#define CACHE_BYTES_GROWTH 131072U // 2**17
#define EPOCH_LENGTH 30000U
#define MIX_BYTES 128
#define DAG_PARENTS 256
#define HASH_BYTES 64
#define DATASET_PARENTS 256
#define CACHE_ROUNDS 3
#define ACCESSES 64
@ -41,8 +43,8 @@ extern "C" {
#endif
typedef struct ethash_params {
size_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
size_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)).
uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)).
} ethash_params;
typedef struct ethash_return_value {
@ -50,29 +52,55 @@ typedef struct ethash_return_value {
uint8_t mix_hash[32];
} ethash_return_value;
size_t ethash_get_datasize(const uint32_t block_number);
size_t ethash_get_cachesize(const uint32_t block_number);
uint64_t ethash_get_datasize(const uint32_t block_number);
uint64_t ethash_get_cachesize(const uint32_t block_number);
// initialize the parameters
static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) {
// Initialize the Parameters
static inline int ethash_params_init(ethash_params *params, const uint32_t block_number) {
params->full_size = ethash_get_datasize(block_number);
if (params->full_size == 0)
return 0;
params->cache_size = ethash_get_cachesize(block_number);
if (params->cache_size == 0)
return 0;
return 1;
}
typedef struct ethash_cache {
void *mem;
void *mem;
} ethash_cache;
void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
int ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
int ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
int ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
int ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number);
static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; ethash_mkcache(&c, params, seed); }
static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void*)cache; ethash_light(ret, &c, params, header_hash, nonce); }
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void*)cache; ethash_compute_full_data(full, params, &c); }
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); }
static inline int ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) {
ethash_cache c;
c.mem = cache;
return ethash_mkcache(&c, params, seed);
}
static inline int ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_cache c;
c.mem = (void *) cache;
return ethash_light(ret, &c, params, header_hash, nonce);
}
static inline int ethash_prep_full(void *full, ethash_params const *params, void const *cache) {
ethash_cache c;
c.mem = (void *) cache;
return ethash_compute_full_data(full, params, &c);
}
static inline int ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
return ethash_full(ret, full, params, header_hash, nonce);
}
// Returns if hash is less than or equal to difficulty
static inline int ethash_check_difficulty(
const uint8_t hash[32],
const uint8_t difficulty[32]) {
@ -81,7 +109,7 @@ static inline int ethash_check_difficulty(
if (hash[i] == difficulty[i]) continue;
return hash[i] < difficulty[i];
}
return 0;
return 1;
}
int ethash_quick_check_difficulty(

View file

@ -1,12 +1,12 @@
/*
This file is part of cpp-ethereum.
This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify
ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@ -14,13 +14,12 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file dash.cpp
/** @file internal.c
* @author Tim Hughes <tim@twistedfury.com>
* @author Matthew Wampler-Doty
* @date 2015
*/
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include "ethash.h"
@ -29,6 +28,9 @@
#include "internal.h"
#include "data_sizes.h"
// Inline assembly doesn't work
#define ENABLE_SSE 0
#ifdef WITH_CRYPTOPP
#include "sha3_cryptopp.h"
@ -37,25 +39,30 @@
#include "sha3.h"
#endif // WITH_CRYPTOPP
size_t ethash_get_datasize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 500);
uint64_t ethash_get_datasize(const uint32_t block_number) {
if (block_number / EPOCH_LENGTH >= 2048)
return 0;
return dag_sizes[block_number / EPOCH_LENGTH];
}
size_t ethash_get_cachesize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 500);
uint64_t ethash_get_cachesize(const uint32_t block_number) {
if (block_number / EPOCH_LENGTH >= 2048)
return 0;
return cache_sizes[block_number / EPOCH_LENGTH];
}
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf
// SeqMemoHash(s, R, N)
void static ethash_compute_cache_nodes(
int static ethash_compute_cache_nodes(
node *const nodes,
ethash_params const *params,
const uint8_t seed[32]) {
assert((params->cache_size % sizeof(node)) == 0);
uint32_t const num_nodes = (uint32_t)(params->cache_size / sizeof(node));
if ((params->cache_size % sizeof(node)) != 0)
return 0;
uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, seed, 32);
@ -68,10 +75,9 @@ void static ethash_compute_cache_nodes(
uint32_t const idx = nodes[i].words[0] % num_nodes;
node data;
data = nodes[(num_nodes - 1 + i) % num_nodes];
for (unsigned w = 0; w != NODE_WORDS; ++w)
{
data.words[w] ^= nodes[idx].words[w];
}
for (unsigned w = 0; w != NODE_WORDS; ++w) {
data.words[w] ^= nodes[idx].words[w];
}
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
}
}
@ -83,29 +89,34 @@ void static ethash_compute_cache_nodes(
nodes->words[w] = fix_endian32(nodes->words[w]);
}
#endif
return 1;
}
void ethash_mkcache(
ethash_cache *cache,
int ethash_mkcache(
ethash_cache *cache,
ethash_params const *params,
const uint8_t seed[32]) {
node *nodes = (node *) cache->mem;
ethash_compute_cache_nodes(nodes, params, seed);
return ethash_compute_cache_nodes(nodes, params, seed);
}
void ethash_calculate_dag_item(
int ethash_calculate_dag_item(
node *const ret,
const unsigned node_index,
const uint64_t node_index,
const struct ethash_params *params,
const struct ethash_cache *cache) {
uint32_t num_parent_nodes = (uint32_t)(params->cache_size / sizeof(node));
if (params->cache_size % sizeof(node) != 0)
return 0;
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache->mem;
node const *init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
@ -115,12 +126,11 @@ void ethash_calculate_dag_item(
__m128i xmm3 = ret->xmm[3];
#endif
for (unsigned i = 0; i != DAG_PARENTS; ++i)
{
uint32_t parent_index = ((node_index ^ i)*FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
for (unsigned i = 0; i != DATASET_PARENTS; ++i) {
uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE
#if defined(_M_X64) && ENABLE_SSE
{
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
@ -143,38 +153,73 @@ void ethash_calculate_dag_item(
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
}
}
#endif
#endif
}
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
return 1;
}
void ethash_compute_full_data(
int ethash_compute_full_data(
void *mem,
ethash_params const *params,
ethash_cache const *cache) {
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0);
assert((params->full_size % sizeof(node)) == 0);
if ((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) != 0)
return 0;
if ((params->full_size % sizeof(node)) != 0)
return 0;
node *full_nodes = mem;
// now compute full nodes
for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) {
for (uint64_t n = 0; n != (params->full_size / sizeof(node)); ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
}
return 1;
}
static void ethash_hash(
ethash_return_value * ret,
int ethash_compute_full_data_section(
void *mem,
ethash_params const *params,
ethash_cache const *cache,
uint64_t const start,
uint64_t const end) {
if ((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) != 0)
return 0;
if ((params->full_size % sizeof(node)) != 0)
return 0;
if (end >= params->full_size)
return 0;
if (start >= end)
return 0;
node *full_nodes = mem;
// now compute full nodes
for (uint64_t n = start; n != end; ++n) {
ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache);
}
return 1;
}
static int ethash_hash(
ethash_return_value *ret,
node const *full_nodes,
ethash_cache const *cache,
ethash_params const *params,
const uint8_t header_hash[32],
const uint64_t nonce) {
assert((params->full_size % MIX_WORDS) == 0);
if ((params->full_size % MIX_WORDS) != 0)
return 0;
// pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node)*8 == 512);
node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, header_hash, 32);
@ -193,23 +238,21 @@ static void ethash_hash(
}
#endif
node* const mix = s_mix + 1;
node *const mix = s_mix + 1;
for (unsigned w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS];
}
unsigned const
page_size = sizeof(uint32_t) * MIX_WORDS,
num_full_pages = (unsigned)(params->full_size / page_size);
num_full_pages = (unsigned) (params->full_size / page_size);
for (unsigned i = 0; i != ACCESSES; ++i)
{
uint32_t const index = ((s_mix->words[0] ^ i)*FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned i = 0; i != ACCESSES; ++i) {
uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n)
{
const node * dag_node = &full_nodes[MIX_NODES * index + n];
for (unsigned n = 0; n != MIX_NODES; ++n) {
const node *dag_node = &full_nodes[MIX_NODES * index + n];
if (!full_nodes) {
node tmp_node;
@ -217,7 +260,7 @@ static void ethash_hash(
dag_node = &tmp_node;
}
#if defined(_M_X64) && ENABLE_SSE
#if defined(_M_X64) && ENABLE_SSE
{
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
@ -235,20 +278,19 @@ static void ethash_hash(
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
}
}
#endif
#endif
}
}
// compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4)
{
uint32_t reduction = mix->words[w+0];
reduction = reduction*FNV_PRIME ^ mix->words[w+1];
reduction = reduction*FNV_PRIME ^ mix->words[w+2];
reduction = reduction*FNV_PRIME ^ mix->words[w+3];
mix->words[w/4] = reduction;
}
// compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4) {
uint32_t reduction = mix->words[w + 0];
reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
mix->words[w / 4] = reduction;
}
#if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != MIX_WORDS/4; ++w) {
@ -258,7 +300,8 @@ static void ethash_hash(
memcpy(ret->mix_hash, mix->bytes, 32);
// final Keccak hash
SHA3_256(ret->result, s_mix->bytes, 64+32); // Keccak-256(s + compressed_mix)
SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
return 1;
}
void ethash_quick_hash(
@ -267,7 +310,7 @@ void ethash_quick_hash(
const uint64_t nonce,
const uint8_t mix_hash[32]) {
uint8_t buf[64+32];
uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32);
#if BYTE_ORDER != LITTLE_ENDIAN
nonce = fix_endian64(nonce);
@ -275,7 +318,14 @@ void ethash_quick_hash(
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64+32);
SHA3_256(return_hash, buf, 64 + 32);
}
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) {
memset(seedhash, 0, 32);
const uint32_t epochs = block_number / EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(seedhash, seedhash, 32);
}
int ethash_quick_check_difficulty(
@ -289,10 +339,10 @@ int ethash_quick_check_difficulty(
return ethash_check_difficulty(return_hash, difficulty);
}
void ethash_full(ethash_return_value * ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
int ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
return ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
}
void ethash_light(ethash_return_value * ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
}
int ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
return ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
}

View file

@ -3,7 +3,7 @@
#include "endian.h"
#include "ethash.h"
#define ENABLE_SSE 1
#define ENABLE_SSE 0
#if defined(_M_X64) && ENABLE_SSE
#include <smmintrin.h>
@ -30,9 +30,9 @@ typedef union node {
} node;
void ethash_calculate_dag_item(
int ethash_calculate_dag_item(
node *const ret,
const unsigned node_index,
const uint64_t node_index,
ethash_params const *params,
ethash_cache const *cache
);

View file

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify
ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file sha3.cpp

View file

@ -1,18 +1,18 @@
/*
This file is part of cpp-ethereum.
This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify
ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file util.h
* @author Tim Hughes <tim@twistedfury.com>

View file

@ -1,64 +1,305 @@
#include <Python.h>
#include <alloca.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include "../libethash/ethash.h"
static PyObject*
get_cache_size(PyObject* self, PyObject* args)
{
#define MIX_WORDS (MIX_BYTES/4)
static PyObject *
get_cache_size(PyObject *self, PyObject *args) {
unsigned long block_number;
if (!PyArg_ParseTuple(args, "k", &block_number))
return 0;
return 0;
if (block_number >= EPOCH_LENGTH * 2048) {
char error_message[1024];
sprintf(error_message, "Block number must be less than %i (was %lu)", EPOCH_LENGTH * 2048, block_number);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
return Py_BuildValue("i", ethash_get_cachesize(block_number));
}
static PyObject*
get_full_size(PyObject* self, PyObject* args)
{
static PyObject *
get_full_size(PyObject *self, PyObject *args) {
unsigned long block_number;
if (!PyArg_ParseTuple(args, "k", &block_number))
return 0;
return 0;
if (block_number >= EPOCH_LENGTH * 2048) {
char error_message[1024];
sprintf(error_message, "Block number must be less than %i (was %lu)", EPOCH_LENGTH * 2048, block_number);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
return Py_BuildValue("i", ethash_get_datasize(block_number));
}
static PyObject*
mkcache(PyObject* self, PyObject* args)
{
char * seed;
static PyObject *
mkcache_bytes(PyObject *self, PyObject *args) {
char *seed;
unsigned long cache_size;
int seed_len;
if (!PyArg_ParseTuple(args, "ks#", &cache_size, &seed, &seed_len))
return 0;
return 0;
if (seed_len != 32)
{
PyErr_SetString(PyExc_ValueError,
"Seed must be 32 bytes long");
return 0;
if (seed_len != 32) {
char error_message[1024];
sprintf(error_message, "Seed must be 32 bytes long (was %i)", seed_len);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
printf("cache size: %lu\n", cache_size);
ethash_params params;
params.cache_size = (size_t) cache_size;
params.cache_size = (uint64_t) cache_size;
ethash_cache cache;
cache.mem = alloca(cache_size);
cache.mem = malloc(cache_size);
ethash_mkcache(&cache, &params, (uint8_t *) seed);
return PyString_FromStringAndSize(cache.mem, cache_size);
PyObject * val = Py_BuildValue("s#", cache.mem, cache_size);
free(cache.mem);
return val;
}
static PyMethodDef CoreMethods[] =
{
{"get_cache_size", get_cache_size, METH_VARARGS, "Get the cache size for a given block number"},
{"get_full_size", get_full_size, METH_VARARGS, "Get the full size for a given block number"},
{"mkcache", mkcache, METH_VARARGS, "Makes the cache for given parameters and seed hash"},
{NULL, NULL, 0, NULL}
};
static PyObject *
calc_dataset_bytes(PyObject *self, PyObject *args) {
char *cache_bytes;
unsigned long full_size;
int cache_size;
if (!PyArg_ParseTuple(args, "ks#", &full_size, &cache_bytes, &cache_size))
return 0;
if (full_size % MIX_WORDS != 0) {
char error_message[1024];
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %lu)", MIX_WORDS, full_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
if (cache_size % HASH_BYTES != 0) {
char error_message[1024];
sprintf(error_message, "The size of the cache must be a multiple of %i bytes (was %i)", HASH_BYTES, cache_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
ethash_params params;
params.cache_size = (uint64_t) cache_size;
params.full_size = (uint64_t) full_size;
ethash_cache cache;
cache.mem = (void *) cache_bytes;
void *mem = malloc(params.full_size);
ethash_compute_full_data(mem, &params, &cache);
PyObject * val = Py_BuildValue("s#", (char *) mem, full_size);
free(mem);
return val;
}
// hashimoto_light(full_size, cache, header, nonce)
static PyObject *
hashimoto_light(PyObject *self, PyObject *args) {
char *cache_bytes, *header;
unsigned long full_size;
unsigned long long nonce;
int cache_size, header_size;
if (!PyArg_ParseTuple(args, "ks#s#K", &full_size, &cache_bytes, &cache_size, &header, &header_size, &nonce))
return 0;
if (full_size % MIX_WORDS != 0) {
char error_message[1024];
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %lu)", MIX_WORDS, full_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
if (cache_size % HASH_BYTES != 0) {
char error_message[1024];
sprintf(error_message, "The size of the cache must be a multiple of %i bytes (was %i)", HASH_BYTES, cache_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
if (header_size != 32) {
char error_message[1024];
sprintf(error_message, "Seed must be 32 bytes long (was %i)", header_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
ethash_return_value out;
ethash_params params;
params.cache_size = (uint64_t) cache_size;
params.full_size = (uint64_t) full_size;
ethash_cache cache;
cache.mem = (void *) cache_bytes;
ethash_light(&out, &cache, &params, (uint8_t *) header, nonce);
return Py_BuildValue("{s:s#,s:s#}",
"mix digest", out.mix_hash, 32,
"result", out.result, 32);
}
// hashimoto_full(dataset, header, nonce)
static PyObject *
hashimoto_full(PyObject *self, PyObject *args) {
char *full_bytes, *header;
unsigned long long nonce;
int full_size, header_size;
if (!PyArg_ParseTuple(args, "s#s#K", &full_bytes, &full_size, &header, &header_size, &nonce))
return 0;
if (full_size % MIX_WORDS != 0) {
char error_message[1024];
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %i)", MIX_WORDS, full_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
if (header_size != 32) {
char error_message[1024];
sprintf(error_message, "Header must be 32 bytes long (was %i)", header_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
ethash_return_value out;
ethash_params params;
params.full_size = (uint64_t) full_size;
ethash_full(&out, (void *) full_bytes, &params, (uint8_t *) header, nonce);
return Py_BuildValue("{s:s#, s:s#}",
"mix digest", out.mix_hash, 32,
"result", out.result, 32);
}
// mine(dataset_bytes, header, difficulty_bytes)
static PyObject *
mine(PyObject *self, PyObject *args) {
char *full_bytes, *header, *difficulty;
srand(time(0));
uint64_t nonce = ((uint64_t) rand()) << 32 | rand();
int full_size, header_size, difficulty_size;
if (!PyArg_ParseTuple(args, "s#s#s#", &full_bytes, &full_size, &header, &header_size, &difficulty, &difficulty_size))
return 0;
if (full_size % MIX_WORDS != 0) {
char error_message[1024];
sprintf(error_message, "The size of data set must be a multiple of %i bytes (was %i)", MIX_WORDS, full_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
if (header_size != 32) {
char error_message[1024];
sprintf(error_message, "Header must be 32 bytes long (was %i)", header_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
if (difficulty_size != 32) {
char error_message[1024];
sprintf(error_message, "Difficulty must be an array of 32 bytes (only had %i)", difficulty_size);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
ethash_return_value out;
ethash_params params;
params.full_size = (uint64_t) full_size;
// TODO: Multi threading?
do {
ethash_full(&out, (void *) full_bytes, &params, (const uint8_t *) header, nonce++);
// TODO: disagrees with the spec https://github.com/ethereum/wiki/wiki/Ethash#mining
} while (!ethash_check_difficulty(out.result, (const uint8_t *) difficulty));
return Py_BuildValue("{s:s#, s:s#, s:K}",
"mix digest", out.mix_hash, 32,
"result", out.result, 32,
"nonce", nonce);
}
//get_seedhash(block_number)
static PyObject *
get_seedhash(PyObject *self, PyObject *args) {
unsigned long block_number;
if (!PyArg_ParseTuple(args, "k", &block_number))
return 0;
if (block_number >= EPOCH_LENGTH * 2048) {
char error_message[1024];
sprintf(error_message, "Block number must be less than %i (was %lu)", EPOCH_LENGTH * 2048, block_number);
PyErr_SetString(PyExc_ValueError, error_message);
return 0;
}
uint8_t seedhash[32];
ethash_get_seedhash(seedhash, block_number);
return Py_BuildValue("s#", (char *) seedhash, 32);
}
static PyMethodDef PyethashMethods[] =
{
{"get_cache_size", get_cache_size, METH_VARARGS,
"get_cache_size(block_number)\n\n"
"Get the cache size for a given block number\n"
"\nExample:\n"
">>> get_cache_size(0)\n"
"1048384"},
{"get_full_size", get_full_size, METH_VARARGS,
"get_full_size(block_number)\n\n"
"Get the full size for a given block number\n"
"\nExample:\n"
">>> get_full_size(0)\n"
"1073739904"
},
{"get_seedhash", get_seedhash, METH_VARARGS,
"get_seedhash(block_number)\n\n"
"Gets the seedhash for a block."},
{"mkcache_bytes", mkcache_bytes, METH_VARARGS,
"mkcache_bytes(size, header)\n\n"
"Makes a byte array for the cache for given cache size and seed hash\n"
"\nExample:\n"
">>> pyethash.mkcache_bytes( 1024, \"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\").encode('hex')"
"\"2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b\""},
{"calc_dataset_bytes", calc_dataset_bytes, METH_VARARGS,
"calc_dataset_bytes(full_size, cache_bytes)\n\n"
"Makes a byte array for the dataset for a given size given cache bytes"},
{"hashimoto_light", hashimoto_light, METH_VARARGS,
"hashimoto_light(full_size, cache_bytes, header, nonce)\n\n"
"Runs the hashimoto hashing function just using cache bytes. Takes an int (full_size), byte array (cache_bytes), another byte array (header), and an int (nonce). Returns an object containing the mix digest, and hash result."},
{"hashimoto_full", hashimoto_full, METH_VARARGS,
"hashimoto_full(dataset_bytes, header, nonce)\n\n"
"Runs the hashimoto hashing function using the dataset bytes. Useful for testing. Returns an object containing the mix digest (byte array), and hash result (another byte array)."},
{"mine", mine, METH_VARARGS,
"mine(dataset_bytes, header, difficulty_bytes)\n\n"
"Mine for an adequate header. Returns an object containing the mix digest (byte array), hash result (another byte array) and nonce (an int)."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initcore(void)
{
(void) Py_InitModule("core", CoreMethods);
initpyethash(void) {
PyObject *module = Py_InitModule("pyethash", PyethashMethods);
// Following Spec: https://github.com/ethereum/wiki/wiki/Ethash#definitions
PyModule_AddIntConstant(module, "REVISION", (long) REVISION);
PyModule_AddIntConstant(module, "DATASET_BYTES_INIT", (long) DATASET_BYTES_INIT);
PyModule_AddIntConstant(module, "DATASET_BYTES_GROWTH", (long) DATASET_BYTES_GROWTH);
PyModule_AddIntConstant(module, "CACHE_BYTES_INIT", (long) CACHE_BYTES_INIT);
PyModule_AddIntConstant(module, "CACHE_BYTES_GROWTH", (long) CACHE_BYTES_GROWTH);
PyModule_AddIntConstant(module, "EPOCH_LENGTH", (long) EPOCH_LENGTH);
PyModule_AddIntConstant(module, "MIX_BYTES", (long) MIX_BYTES);
PyModule_AddIntConstant(module, "HASH_BYTES", (long) HASH_BYTES);
PyModule_AddIntConstant(module, "DATASET_PARENTS", (long) DATASET_PARENTS);
PyModule_AddIntConstant(module, "CACHE_ROUNDS", (long) CACHE_ROUNDS);
PyModule_AddIntConstant(module, "ACCESSES", (long) ACCESSES);
}

View file

@ -4,7 +4,9 @@
#include <libethash/internal.h>
#ifdef WITH_CRYPTOPP
#include <libethash/sha3_cryptopp.h>
#else
#include <libethash/sha3.h>
#endif // WITH_CRYPTOPP
@ -15,7 +17,7 @@
#include <boost/test/unit_test.hpp>
#include <iostream>
std::string bytesToHexString(const uint8_t *str, const size_t s) {
std::string bytesToHexString(const uint8_t *str, const uint32_t s) {
std::ostringstream ret;
for (int i = 0; i < s; ++i)
@ -28,7 +30,7 @@ BOOST_AUTO_TEST_CASE(fnv_hash_check) {
uint32_t x = 1235U;
const uint32_t
y = 9999999U,
expected = (FNV_PRIME * x) ^ y;
expected = (FNV_PRIME * x) ^y;
x = fnv_hash(x, y);
@ -65,43 +67,52 @@ BOOST_AUTO_TEST_CASE(SHA512_check) {
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) {
ethash_params params;
ethash_params_init(&params, 0);
BOOST_REQUIRE_MESSAGE(params.full_size < DAGSIZE_BYTES_INIT,
BOOST_REQUIRE_MESSAGE(params.full_size < DATASET_BYTES_INIT,
"\nfull size: " << params.full_size << "\n"
<< "should be less than or equal to: " << DAGSIZE_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.full_size + 20*MIX_BYTES >= DAGSIZE_BYTES_INIT,
"\nfull size + 20*MIX_BYTES: " << params.full_size + 20*MIX_BYTES << "\n"
<< "should be greater than or equal to: " << DAGSIZE_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size < DAGSIZE_BYTES_INIT / 32,
<< "should be less than or equal to: " << DATASET_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.full_size + 20 * MIX_BYTES >= DATASET_BYTES_INIT,
"\nfull size + 20*MIX_BYTES: " << params.full_size + 20 * MIX_BYTES << "\n"
<< "should be greater than or equal to: " << DATASET_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size < DATASET_BYTES_INIT / 32,
"\ncache size: " << params.cache_size << "\n"
<< "should be less than or equal to: " << DAGSIZE_BYTES_INIT / 32 << "\n");
<< "should be less than or equal to: " << DATASET_BYTES_INIT / 32 << "\n");
}
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) {
ethash_params params;
ethash_params_init(&params, 0);
const uint32_t expected_full_size = 1073739904;
const uint32_t expected_cache_size = 1048384;
BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size,
BOOST_REQUIRE_MESSAGE(ethash_params_init(&params, 0),
"Params could not be initialized");
const uint32_t
expected_full_size = 1073739904,
expected_cache_size = 16776896;
BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size,
"\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.full_size << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size == expected_cache_size,
BOOST_REQUIRE_MESSAGE(params.cache_size == expected_cache_size,
"\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.cache_size << "\n");
}
BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
ethash_params params;
uint8_t seed[32], hash[32];
uint8_t seed[32], hash[32], difficulty[32];
ethash_return_value light_out, full_out;
memcpy(seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
memcpy(hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
// Set the difficulty
difficulty[0] = 197;
difficulty[1] = 90;
for (int i = 2; i < 32; i++)
difficulty[i] = (uint8_t) 255;
ethash_params_init(&params, 0);
params.cache_size = 1024;
params.full_size = 1024 * 32;
ethash_cache cache;
cache.mem = alloca(params.cache_size);
ethash_mkcache(&cache, &params, seed);
node * full_mem = (node *) alloca(params.full_size);
node *full_mem = (node *) alloca(params.full_size);
ethash_compute_full_data(full_mem, &params, &cache);
{
@ -115,7 +126,6 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
}
{
node node;
ethash_calculate_dag_item(&node, 0, &params, &cache);
@ -128,7 +138,7 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
}
{
for (int i = 0 ; i < params.full_size / sizeof(node) ; ++i ) {
for (int i = 0; i < params.full_size / sizeof(node); ++i) {
for (uint32_t j = 0; j < 32; ++j) {
node expected_node;
ethash_calculate_dag_item(&expected_node, j, &params, &cache);
@ -187,6 +197,12 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n");
BOOST_REQUIRE_MESSAGE(ethash_check_difficulty(full_out.result, difficulty),
"ethash_check_difficulty failed"
);
BOOST_REQUIRE_MESSAGE(ethash_quick_check_difficulty(hash, 5U, full_out.mix_hash, difficulty),
"ethash_quick_check_difficulty failed"
);
}
}
@ -199,14 +215,14 @@ BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) {
memcpy(target, "22222222222222222222222222222222", 32);
BOOST_REQUIRE_MESSAGE(
ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have less difficulty than \"" << target << "\"\n");
"\nexpected \"" << std::string((char *) hash, 32).c_str() << "\" to have the same or less difficulty than \"" << std::string((char *) target, 32).c_str() << "\"\n");
BOOST_REQUIRE_MESSAGE(
!ethash_check_difficulty(hash, hash),
"\nexpected \"" << hash << "\" to have the same difficulty as \"" << hash << "\"\n");
ethash_check_difficulty(hash, hash),
"\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << hash << "\"\n");
memcpy(target, "11111111111111111111111111111112", 32);
BOOST_REQUIRE_MESSAGE(
ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have less difficulty than \"" << target << "\"\n");
"\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << target << "\"\n");
memcpy(target, "11111111111111111111111111111110", 32);
BOOST_REQUIRE_MESSAGE(
!ethash_check_difficulty(hash, target),

View file

@ -0,0 +1,82 @@
package ethashTest
import (
"bytes"
"crypto/rand"
"encoding/hex"
"log"
"math/big"
"testing"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethdb"
)
func TestEthash(t *testing.T) {
seedHash := make([]byte, 32)
_, err := rand.Read(seedHash)
if err != nil {
panic(err)
}
db, err := ethdb.NewMemDatabase()
if err != nil {
panic(err)
}
blockProcessor, err := core.NewCanonical(5, db)
if err != nil {
panic(err)
}
log.Println("Block Number: ", blockProcessor.ChainManager().CurrentBlock().Number())
e := ethash.New(blockProcessor.ChainManager())
miningHash := make([]byte, 32)
if _, err := rand.Read(miningHash); err != nil {
panic(err)
}
diff := big.NewInt(10000)
log.Println("difficulty", diff)
nonce := uint64(0)
ghash_full := e.FullHash(nonce, miningHash)
log.Printf("ethash full (on nonce): %x %x\n", ghash_full, nonce)
ghash_light := e.LightHash(nonce, miningHash)
log.Printf("ethash light (on nonce): %x %x\n", ghash_light, nonce)
if bytes.Compare(ghash_full, ghash_light) != 0 {
t.Errorf("full: %x, light: %x", ghash_full, ghash_light)
}
}
func TestGetSeedHash(t *testing.T) {
seed0, err := ethash.GetSeedHash(0)
if err != nil {
t.Errorf("Failed to get seedHash for block 0: %v", err)
}
if bytes.Compare(seed0, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) != 0 {
log.Printf("seedHash for block 0 should be 0s, was: %v\n", seed0)
}
seed1, err := ethash.GetSeedHash(30000)
if err != nil {
t.Error(err)
}
// From python:
// > from pyethash import get_seedhash
// > get_seedhash(30000)
expectedSeed1, err := hex.DecodeString("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
if err != nil {
t.Error(err)
}
if bytes.Compare(seed1, expectedSeed1) != 0 {
log.Printf("seedHash for block 1 should be: %v,\nactual value: %v\n", expectedSeed1, seed1)
}
}

View file

@ -0,0 +1,20 @@
#!/bin/bash
# Strict mode
set -e
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
export GOPATH=${HOME}/.go
export PATH=$PATH:$GOPATH/bin
echo "# getting go dependencies (can take some time)..."
cd ${TEST_DIR}/../.. && go get
cd ${GOPATH}/src/github.com/ethereum/go-ethereum
git checkout poc-9
cd ${TEST_DIR} && go test

View file

@ -1,2 +1,3 @@
pyethereum==0.7.522
nose==1.3.4
pysha3==0.3

View file

@ -14,6 +14,6 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
[ -d $TEST_DIR/python-virtual-env ] || virtualenv --system-site-packages $TEST_DIR/python-virtual-env
source $TEST_DIR/python-virtual-env/bin/activate
pip install -r $TEST_DIR/requirements.txt > /dev/null
pip install -e $TEST_DIR/../.. > /dev/null
pip install --upgrade --no-deps --force-reinstall -e $TEST_DIR/../..
cd $TEST_DIR
nosetests --with-doctest -v
nosetests --with-doctest -v --nocapture

View file

@ -4,42 +4,102 @@ from random import randint
def test_get_cache_size_not_None():
for _ in range(100):
block_num = randint(0,12456789)
out = pyethash.core.get_cache_size(block_num)
out = pyethash.get_cache_size(block_num)
assert out != None
def test_get_full_size_not_None():
for _ in range(100):
block_num = randint(0,12456789)
out = pyethash.core.get_full_size(block_num)
out = pyethash.get_full_size(block_num)
assert out != None
def test_get_cache_size_based_on_EPOCH():
for _ in range(100):
block_num = randint(0,12456789)
out1 = pyethash.core.get_cache_size(block_num)
out2 = pyethash.core.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
out1 = pyethash.get_cache_size(block_num)
out2 = pyethash.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
assert out1 == out2
def test_get_full_size_based_on_EPOCH():
for _ in range(100):
block_num = randint(0,12456789)
out1 = pyethash.core.get_full_size(block_num)
out2 = pyethash.core.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
out1 = pyethash.get_full_size(block_num)
out2 = pyethash.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
assert out1 == out2
#def test_get_params_based_on_EPOCH():
# block_num = 123456
# out1 = pyethash.core.get_params(block_num)
# out2 = pyethash.core.get_params((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
# assert out1["DAG Size"] == out2["DAG Size"]
# assert out1["Cache Size"] == out2["Cache Size"]
#
#def test_get_params_returns_different_values_based_on_different_block_input():
# out1 = pyethash.core.get_params(123456)
# out2 = pyethash.core.get_params(12345)
# assert out1["DAG Size"] != out2["DAG Size"]
# assert out1["Cache Size"] != out2["Cache Size"]
#
#def test_get_cache_smoke_test():
# params = pyethash.core.get_params(123456)
# assert pyethash.core.mkcache(params, "~~~~") != None
# See light_and_full_client_checks in test.cpp
def test_mkcache_is_as_expected():
actual = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~").encode('hex')
expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b"
assert actual == expected
def test_calc_dataset_is_not_None():
cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
assert pyethash.calc_dataset_bytes(1024 * 32, cache) != None
def test_light_and_full_agree():
cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
full_size = 1024 * 32
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
light_result = pyethash.hashimoto_light(full_size, cache, header, 0)
dataset = pyethash.calc_dataset_bytes(full_size, cache)
full_result = pyethash.hashimoto_full(dataset, header, 0)
assert light_result["mix digest"] != None
assert len(light_result["mix digest"]) == 32
assert light_result["mix digest"] == full_result["mix digest"]
assert light_result["result"] != None
assert len(light_result["result"]) == 32
assert light_result["result"] == full_result["result"]
def int_to_bytes(i):
b = []
for _ in range(32):
b.append(chr(i & 0xff))
i >>= 8
b.reverse()
return "".join(b)
def test_mining_basic():
easy_difficulty = int_to_bytes(2**256 - 1)
assert easy_difficulty.encode('hex') == 'f' * 64
cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
full_size = 1024 * 32
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
dataset = pyethash.calc_dataset_bytes(full_size, cache)
# Check type of outputs
assert type(pyethash.mine(dataset,header,easy_difficulty)) == dict
assert type(pyethash.mine(dataset,header,easy_difficulty)["nonce"]) == long
assert type(pyethash.mine(dataset,header,easy_difficulty)["mix digest"]) == str
assert type(pyethash.mine(dataset,header,easy_difficulty)["result"]) == str
def test_mining_doesnt_always_return_the_same_value():
easy_difficulty1 = int_to_bytes(int(2**256 * 0.999))
# 1 in 1000 difficulty
easy_difficulty2 = int_to_bytes(int(2**256 * 0.001))
assert easy_difficulty1 != easy_difficulty2
cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
full_size = 1024 * 32
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
dataset = pyethash.calc_dataset_bytes(full_size, cache)
# Check type of outputs
assert pyethash.mine(dataset, header, easy_difficulty1)['nonce'] != pyethash.mine(dataset, header, easy_difficulty2)['nonce']
def test_get_seedhash():
assert pyethash.get_seedhash(0).encode('hex') == '0' * 64
import hashlib, sha3
expected = pyethash.get_seedhash(0)
#print "checking seed hashes:",
for i in range(0, 30000*2048, 30000):
#print i // 30000,
assert pyethash.get_seedhash(i) == expected
expected = hashlib.sha3_256(expected).digest()

View file

@ -14,7 +14,9 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo -e "\n################# Testing JS ##################"
# TODO: Use mocha and real testing tools instead of rolling our own
cd $TEST_DIR/../js
node test.js
if [ -x "$(which npm)" ] ; then
npm test
fi
echo -e "\n################# Testing C ##################"
$TEST_DIR/c/test.sh

File diff suppressed because it is too large Load diff

View file

@ -1,496 +0,0 @@
/*
Package ast declares types representing a JavaScript AST.
Warning
The parser and AST interfaces are still works-in-progress (particularly where
node types are concerned) and may change in the future.
*/
package ast
import (
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
// All nodes implement the Node interface.
type Node interface {
Idx0() file.Idx // The index of the first character belonging to the node
Idx1() file.Idx // The index of the first character immediately after the node
}
// ========== //
// Expression //
// ========== //
type (
// All expression nodes implement the Expression interface.
Expression interface {
Node
_expressionNode()
}
ArrayLiteral struct {
LeftBracket file.Idx
RightBracket file.Idx
Value []Expression
}
AssignExpression struct {
Operator token.Token
Left Expression
Right Expression
}
BadExpression struct {
From file.Idx
To file.Idx
}
BinaryExpression struct {
Operator token.Token
Left Expression
Right Expression
Comparison bool
}
BooleanLiteral struct {
Idx file.Idx
Literal string
Value bool
}
BracketExpression struct {
Left Expression
Member Expression
LeftBracket file.Idx
RightBracket file.Idx
}
CallExpression struct {
Callee Expression
LeftParenthesis file.Idx
ArgumentList []Expression
RightParenthesis file.Idx
}
ConditionalExpression struct {
Test Expression
Consequent Expression
Alternate Expression
}
DotExpression struct {
Left Expression
Identifier Identifier
}
FunctionLiteral struct {
Function file.Idx
Name *Identifier
ParameterList *ParameterList
Body Statement
Source string
DeclarationList []Declaration
}
Identifier struct {
Name string
Idx file.Idx
}
NewExpression struct {
New file.Idx
Callee Expression
LeftParenthesis file.Idx
ArgumentList []Expression
RightParenthesis file.Idx
}
NullLiteral struct {
Idx file.Idx
Literal string
}
NumberLiteral struct {
Idx file.Idx
Literal string
Value interface{}
}
ObjectLiteral struct {
LeftBrace file.Idx
RightBrace file.Idx
Value []Property
}
ParameterList struct {
Opening file.Idx
List []*Identifier
Closing file.Idx
}
Property struct {
Key string
Kind string
Value Expression
}
RegExpLiteral struct {
Idx file.Idx
Literal string
Pattern string
Flags string
Value string
}
SequenceExpression struct {
Sequence []Expression
}
StringLiteral struct {
Idx file.Idx
Literal string
Value string
}
ThisExpression struct {
Idx file.Idx
}
UnaryExpression struct {
Operator token.Token
Idx file.Idx // If a prefix operation
Operand Expression
Postfix bool
}
VariableExpression struct {
Name string
Idx file.Idx
Initializer Expression
}
)
// _expressionNode
func (*ArrayLiteral) _expressionNode() {}
func (*AssignExpression) _expressionNode() {}
func (*BadExpression) _expressionNode() {}
func (*BinaryExpression) _expressionNode() {}
func (*BooleanLiteral) _expressionNode() {}
func (*BracketExpression) _expressionNode() {}
func (*CallExpression) _expressionNode() {}
func (*ConditionalExpression) _expressionNode() {}
func (*DotExpression) _expressionNode() {}
func (*FunctionLiteral) _expressionNode() {}
func (*Identifier) _expressionNode() {}
func (*NewExpression) _expressionNode() {}
func (*NullLiteral) _expressionNode() {}
func (*NumberLiteral) _expressionNode() {}
func (*ObjectLiteral) _expressionNode() {}
func (*RegExpLiteral) _expressionNode() {}
func (*SequenceExpression) _expressionNode() {}
func (*StringLiteral) _expressionNode() {}
func (*ThisExpression) _expressionNode() {}
func (*UnaryExpression) _expressionNode() {}
func (*VariableExpression) _expressionNode() {}
// ========= //
// Statement //
// ========= //
type (
// All statement nodes implement the Statement interface.
Statement interface {
Node
_statementNode()
}
BadStatement struct {
From file.Idx
To file.Idx
}
BlockStatement struct {
LeftBrace file.Idx
List []Statement
RightBrace file.Idx
}
BranchStatement struct {
Idx file.Idx
Token token.Token
Label *Identifier
}
CaseStatement struct {
Case file.Idx
Test Expression
Consequent []Statement
}
CatchStatement struct {
Catch file.Idx
Parameter *Identifier
Body Statement
}
DebuggerStatement struct {
Debugger file.Idx
}
DoWhileStatement struct {
Do file.Idx
Test Expression
Body Statement
}
EmptyStatement struct {
Semicolon file.Idx
}
ExpressionStatement struct {
Expression Expression
}
ForInStatement struct {
For file.Idx
Into Expression
Source Expression
Body Statement
}
ForStatement struct {
For file.Idx
Initializer Expression
Update Expression
Test Expression
Body Statement
}
IfStatement struct {
If file.Idx
Test Expression
Consequent Statement
Alternate Statement
}
LabelledStatement struct {
Label *Identifier
Colon file.Idx
Statement Statement
}
ReturnStatement struct {
Return file.Idx
Argument Expression
}
SwitchStatement struct {
Switch file.Idx
Discriminant Expression
Default int
Body []*CaseStatement
}
ThrowStatement struct {
Throw file.Idx
Argument Expression
}
TryStatement struct {
Try file.Idx
Body Statement
Catch *CatchStatement
Finally Statement
}
VariableStatement struct {
Var file.Idx
List []Expression
}
WhileStatement struct {
While file.Idx
Test Expression
Body Statement
}
WithStatement struct {
With file.Idx
Object Expression
Body Statement
}
)
// _statementNode
func (*BadStatement) _statementNode() {}
func (*BlockStatement) _statementNode() {}
func (*BranchStatement) _statementNode() {}
func (*CaseStatement) _statementNode() {}
func (*CatchStatement) _statementNode() {}
func (*DebuggerStatement) _statementNode() {}
func (*DoWhileStatement) _statementNode() {}
func (*EmptyStatement) _statementNode() {}
func (*ExpressionStatement) _statementNode() {}
func (*ForInStatement) _statementNode() {}
func (*ForStatement) _statementNode() {}
func (*IfStatement) _statementNode() {}
func (*LabelledStatement) _statementNode() {}
func (*ReturnStatement) _statementNode() {}
func (*SwitchStatement) _statementNode() {}
func (*ThrowStatement) _statementNode() {}
func (*TryStatement) _statementNode() {}
func (*VariableStatement) _statementNode() {}
func (*WhileStatement) _statementNode() {}
func (*WithStatement) _statementNode() {}
// =========== //
// Declaration //
// =========== //
type (
// All declaration nodes implement the Declaration interface.
Declaration interface {
_declarationNode()
}
FunctionDeclaration struct {
Function *FunctionLiteral
}
VariableDeclaration struct {
Var file.Idx
List []*VariableExpression
}
)
// _declarationNode
func (*FunctionDeclaration) _declarationNode() {}
func (*VariableDeclaration) _declarationNode() {}
// ==== //
// Node //
// ==== //
type Program struct {
Body []Statement
DeclarationList []Declaration
}
// ==== //
// Idx0 //
// ==== //
func (self *ArrayLiteral) Idx0() file.Idx { return self.LeftBracket }
func (self *AssignExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *BadExpression) Idx0() file.Idx { return self.From }
func (self *BinaryExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *BooleanLiteral) Idx0() file.Idx { return self.Idx }
func (self *BracketExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *CallExpression) Idx0() file.Idx { return self.Callee.Idx0() }
func (self *ConditionalExpression) Idx0() file.Idx { return self.Test.Idx0() }
func (self *DotExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *FunctionLiteral) Idx0() file.Idx { return self.Function }
func (self *Identifier) Idx0() file.Idx { return self.Idx }
func (self *NewExpression) Idx0() file.Idx { return self.New }
func (self *NullLiteral) Idx0() file.Idx { return self.Idx }
func (self *NumberLiteral) Idx0() file.Idx { return self.Idx }
func (self *ObjectLiteral) Idx0() file.Idx { return self.LeftBrace }
func (self *RegExpLiteral) Idx0() file.Idx { return self.Idx }
func (self *SequenceExpression) Idx0() file.Idx { return self.Sequence[0].Idx0() }
func (self *StringLiteral) Idx0() file.Idx { return self.Idx }
func (self *ThisExpression) Idx0() file.Idx { return self.Idx }
func (self *UnaryExpression) Idx0() file.Idx { return self.Idx }
func (self *VariableExpression) Idx0() file.Idx { return self.Idx }
func (self *BadStatement) Idx0() file.Idx { return self.From }
func (self *BlockStatement) Idx0() file.Idx { return self.LeftBrace }
func (self *BranchStatement) Idx0() file.Idx { return self.Idx }
func (self *CaseStatement) Idx0() file.Idx { return self.Case }
func (self *CatchStatement) Idx0() file.Idx { return self.Catch }
func (self *DebuggerStatement) Idx0() file.Idx { return self.Debugger }
func (self *DoWhileStatement) Idx0() file.Idx { return self.Do }
func (self *EmptyStatement) Idx0() file.Idx { return self.Semicolon }
func (self *ExpressionStatement) Idx0() file.Idx { return self.Expression.Idx0() }
func (self *ForInStatement) Idx0() file.Idx { return self.For }
func (self *ForStatement) Idx0() file.Idx { return self.For }
func (self *IfStatement) Idx0() file.Idx { return self.If }
func (self *LabelledStatement) Idx0() file.Idx { return self.Label.Idx0() }
func (self *Program) Idx0() file.Idx { return self.Body[0].Idx0() }
func (self *ReturnStatement) Idx0() file.Idx { return self.Return }
func (self *SwitchStatement) Idx0() file.Idx { return self.Switch }
func (self *ThrowStatement) Idx0() file.Idx { return self.Throw }
func (self *TryStatement) Idx0() file.Idx { return self.Try }
func (self *VariableStatement) Idx0() file.Idx { return self.Var }
func (self *WhileStatement) Idx0() file.Idx { return self.While }
func (self *WithStatement) Idx0() file.Idx { return self.With }
// ==== //
// Idx1 //
// ==== //
func (self *ArrayLiteral) Idx1() file.Idx { return self.RightBracket }
func (self *AssignExpression) Idx1() file.Idx { return self.Right.Idx1() }
func (self *BadExpression) Idx1() file.Idx { return self.To }
func (self *BinaryExpression) Idx1() file.Idx { return self.Right.Idx1() }
func (self *BooleanLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *BracketExpression) Idx1() file.Idx { return self.RightBracket + 1 }
func (self *CallExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
func (self *ConditionalExpression) Idx1() file.Idx { return self.Test.Idx1() }
func (self *DotExpression) Idx1() file.Idx { return self.Identifier.Idx1() }
func (self *FunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() }
func (self *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) }
func (self *NewExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
func (self *NullLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + 4) } // "null"
func (self *NumberLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *ObjectLiteral) Idx1() file.Idx { return self.RightBrace }
func (self *RegExpLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *SequenceExpression) Idx1() file.Idx { return self.Sequence[0].Idx1() }
func (self *StringLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *ThisExpression) Idx1() file.Idx { return self.Idx }
func (self *UnaryExpression) Idx1() file.Idx {
if self.Postfix {
return self.Operand.Idx1() + 2 // ++ --
}
return self.Operand.Idx1()
}
func (self *VariableExpression) Idx1() file.Idx {
if self.Initializer == nil {
return file.Idx(int(self.Idx) + len(self.Name) + 1)
}
return self.Initializer.Idx1()
}
func (self *BadStatement) Idx1() file.Idx { return self.To }
func (self *BlockStatement) Idx1() file.Idx { return self.RightBrace + 1 }
func (self *BranchStatement) Idx1() file.Idx { return self.Idx }
func (self *CaseStatement) Idx1() file.Idx { return self.Consequent[len(self.Consequent)-1].Idx1() }
func (self *CatchStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *DebuggerStatement) Idx1() file.Idx { return self.Debugger + 8 }
func (self *DoWhileStatement) Idx1() file.Idx { return self.Test.Idx1() }
func (self *EmptyStatement) Idx1() file.Idx { return self.Semicolon + 1 }
func (self *ExpressionStatement) Idx1() file.Idx { return self.Expression.Idx1() }
func (self *ForInStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *ForStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *IfStatement) Idx1() file.Idx {
if self.Alternate != nil {
return self.Alternate.Idx1()
}
return self.Consequent.Idx1()
}
func (self *LabelledStatement) Idx1() file.Idx { return self.Colon + 1 }
func (self *Program) Idx1() file.Idx { return self.Body[len(self.Body)-1].Idx1() }
func (self *ReturnStatement) Idx1() file.Idx { return self.Return }
func (self *SwitchStatement) Idx1() file.Idx { return self.Body[len(self.Body)-1].Idx1() }
func (self *ThrowStatement) Idx1() file.Idx { return self.Throw }
func (self *TryStatement) Idx1() file.Idx { return self.Try }
func (self *VariableStatement) Idx1() file.Idx { return self.List[len(self.List)-1].Idx1() }
func (self *WhileStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *WithStatement) Idx1() file.Idx { return self.Body.Idx1() }

View file

@ -1,85 +0,0 @@
package otto
func (runtime *_runtime) newEvalError(message Value) *_object {
self := runtime.newErrorObject(message)
self.prototype = runtime.Global.EvalErrorPrototype
return self
}
func builtinEvalError(call FunctionCall) Value {
return toValue_object(call.runtime.newEvalError(call.Argument(0)))
}
func builtinNewEvalError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newEvalError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newTypeError(message Value) *_object {
self := runtime.newErrorObject(message)
self.prototype = runtime.Global.TypeErrorPrototype
return self
}
func builtinTypeError(call FunctionCall) Value {
return toValue_object(call.runtime.newTypeError(call.Argument(0)))
}
func builtinNewTypeError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newTypeError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newRangeError(message Value) *_object {
self := runtime.newErrorObject(message)
self.prototype = runtime.Global.RangeErrorPrototype
return self
}
func builtinRangeError(call FunctionCall) Value {
return toValue_object(call.runtime.newRangeError(call.Argument(0)))
}
func builtinNewRangeError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newRangeError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newURIError(message Value) *_object {
self := runtime.newErrorObject(message)
self.prototype = runtime.Global.URIErrorPrototype
return self
}
func (runtime *_runtime) newReferenceError(message Value) *_object {
self := runtime.newErrorObject(message)
self.prototype = runtime.Global.ReferenceErrorPrototype
return self
}
func builtinReferenceError(call FunctionCall) Value {
return toValue_object(call.runtime.newReferenceError(call.Argument(0)))
}
func builtinNewReferenceError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newReferenceError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newSyntaxError(message Value) *_object {
self := runtime.newErrorObject(message)
self.prototype = runtime.Global.SyntaxErrorPrototype
return self
}
func builtinSyntaxError(call FunctionCall) Value {
return toValue_object(call.runtime.newSyntaxError(call.Argument(0)))
}
func builtinNewSyntaxError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newSyntaxError(valueOfArrayIndex(argumentList, 0)))
}
func builtinURIError(call FunctionCall) Value {
return toValue_object(call.runtime.newURIError(call.Argument(0)))
}
func builtinNewURIError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newURIError(valueOfArrayIndex(argumentList, 0)))
}

View file

@ -1,144 +0,0 @@
package otto
import (
"fmt"
)
type _clone struct {
runtime *_runtime
stash struct {
object map[*_object]*_object
objectEnvironment map[*_objectEnvironment]*_objectEnvironment
declarativeEnvironment map[*_declarativeEnvironment]*_declarativeEnvironment
}
}
func (runtime *_runtime) clone() *_runtime {
self := &_runtime{}
clone := &_clone{
runtime: self,
}
clone.stash.object = make(map[*_object]*_object)
clone.stash.objectEnvironment = make(map[*_objectEnvironment]*_objectEnvironment)
clone.stash.declarativeEnvironment = make(map[*_declarativeEnvironment]*_declarativeEnvironment)
globalObject := clone.object(runtime.GlobalObject)
self.GlobalEnvironment = self.newObjectEnvironment(globalObject, nil)
self.GlobalObject = globalObject
self.Global = _global{
clone.object(runtime.Global.Object),
clone.object(runtime.Global.Function),
clone.object(runtime.Global.Array),
clone.object(runtime.Global.String),
clone.object(runtime.Global.Boolean),
clone.object(runtime.Global.Number),
clone.object(runtime.Global.Math),
clone.object(runtime.Global.Date),
clone.object(runtime.Global.RegExp),
clone.object(runtime.Global.Error),
clone.object(runtime.Global.EvalError),
clone.object(runtime.Global.TypeError),
clone.object(runtime.Global.RangeError),
clone.object(runtime.Global.ReferenceError),
clone.object(runtime.Global.SyntaxError),
clone.object(runtime.Global.URIError),
clone.object(runtime.Global.JSON),
clone.object(runtime.Global.ObjectPrototype),
clone.object(runtime.Global.FunctionPrototype),
clone.object(runtime.Global.ArrayPrototype),
clone.object(runtime.Global.StringPrototype),
clone.object(runtime.Global.BooleanPrototype),
clone.object(runtime.Global.NumberPrototype),
clone.object(runtime.Global.DatePrototype),
clone.object(runtime.Global.RegExpPrototype),
clone.object(runtime.Global.ErrorPrototype),
clone.object(runtime.Global.EvalErrorPrototype),
clone.object(runtime.Global.TypeErrorPrototype),
clone.object(runtime.Global.RangeErrorPrototype),
clone.object(runtime.Global.ReferenceErrorPrototype),
clone.object(runtime.Global.SyntaxErrorPrototype),
clone.object(runtime.Global.URIErrorPrototype),
}
self.EnterGlobalExecutionContext()
self.eval = self.GlobalObject.property["eval"].value.(Value).value.(*_object)
self.GlobalObject.prototype = self.Global.ObjectPrototype
return self
}
func (clone *_clone) object(self0 *_object) *_object {
if self1, exists := clone.stash.object[self0]; exists {
return self1
}
self1 := &_object{}
clone.stash.object[self0] = self1
return self0.objectClass.clone(self0, self1, clone)
}
func (clone *_clone) declarativeEnvironment(self0 *_declarativeEnvironment) (*_declarativeEnvironment, bool) {
if self1, exists := clone.stash.declarativeEnvironment[self0]; exists {
return self1, true
}
self1 := &_declarativeEnvironment{}
clone.stash.declarativeEnvironment[self0] = self1
return self1, false
}
func (clone *_clone) objectEnvironment(self0 *_objectEnvironment) (*_objectEnvironment, bool) {
if self1, exists := clone.stash.objectEnvironment[self0]; exists {
return self1, true
}
self1 := &_objectEnvironment{}
clone.stash.objectEnvironment[self0] = self1
return self1, false
}
func (clone *_clone) value(self0 Value) Value {
self1 := self0
switch value := self0.value.(type) {
case *_object:
self1.value = clone.object(value)
}
return self1
}
func (clone *_clone) valueArray(self0 []Value) []Value {
self1 := make([]Value, len(self0))
for index, value := range self0 {
self1[index] = clone.value(value)
}
return self1
}
func (clone *_clone) environment(self0 _environment) _environment {
if self0 == nil {
return nil
}
return self0.clone(clone)
}
func (clone *_clone) property(self0 _property) _property {
self1 := self0
if value, valid := self0.value.(Value); valid {
self1.value = clone.value(value)
} else {
panic(fmt.Errorf("self0.value.(Value) != true"))
}
return self1
}
func (clone *_clone) declarativeProperty(self0 _declarativeProperty) _declarativeProperty {
self1 := self0
self1.value = clone.value(self0.value)
return self1
}
func (clone *_clone) callFunction(self0 _callFunction) _callFunction {
if self0 == nil {
return nil
}
return self0.clone(clone)
}

View file

@ -1,46 +0,0 @@
package otto
// _cmpl_nodeCallFunction
type _cmpl_nodeCallFunction struct {
node *_nodeFunctionLiteral
scopeEnvironment _environment // Can be either Lexical or Variable
}
func new_nodeCallFunction(node *_nodeFunctionLiteral, scopeEnvironment _environment) *_cmpl_nodeCallFunction {
self := &_cmpl_nodeCallFunction{
node: node,
}
self.scopeEnvironment = scopeEnvironment
return self
}
func (self _cmpl_nodeCallFunction) Dispatch(function *_object, environment *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, _ bool) Value {
return runtime.cmpl_call_nodeFunction(function, environment, self.node, this, argumentList)
}
func (self _cmpl_nodeCallFunction) ScopeEnvironment() _environment {
return self.scopeEnvironment
}
func (self _cmpl_nodeCallFunction) Source(object *_object) string {
return self.node.source
}
func (self0 _cmpl_nodeCallFunction) clone(clone *_clone) _callFunction {
return _cmpl_nodeCallFunction{
node: self0.node,
scopeEnvironment: clone.environment(self0.scopeEnvironment),
}
}
// ---
func (runtime *_runtime) newNodeFunctionObject(node *_nodeFunctionLiteral, scopeEnvironment _environment) *_object {
self := runtime.newClassObject("Function")
self.value = _functionObject{
call: new_nodeCallFunction(node, scopeEnvironment),
construct: defaultConstructFunction,
}
self.defineProperty("length", toValue_int(len(node.parameterList)), 0000, false)
return self
}

View file

@ -1,387 +0,0 @@
// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) from github.com/robertkrimen/dbg
/*
Package dbg is a println/printf/log-debugging utility library.
import (
Dbg "github.com/robertkrimen/dbg"
)
dbg, dbgf := Dbg.New()
dbg("Emit some debug stuff", []byte{120, 121, 122, 122, 121}, math.Pi)
# "2013/01/28 16:50:03 Emit some debug stuff [120 121 122 122 121] 3.141592653589793"
dbgf("With a %s formatting %.2f", "little", math.Pi)
# "2013/01/28 16:51:55 With a little formatting (3.14)"
dbgf("%/fatal//A fatal debug statement: should not be here")
# "A fatal debug statement: should not be here"
# ...and then, os.Exit(1)
dbgf("%/panic//Can also panic %s", "this")
# "Can also panic this"
# ...as a panic, equivalent to: panic("Can also panic this")
dbgf("Any %s arguments without a corresponding %%", "extra", "are treated like arguments to dbg()")
# "2013/01/28 17:14:40 Any extra arguments (without a corresponding %) are treated like arguments to dbg()"
dbgf("%d %d", 1, 2, 3, 4, 5)
# "2013/01/28 17:16:32 Another example: 1 2 3 4 5"
dbgf("%@: Include the function name for a little context (via %s)", "%@")
# "2013... github.com/robertkrimen/dbg.TestSynopsis: Include the function name for a little context (via %@)"
By default, dbg uses log (log.Println, log.Printf, log.Panic, etc.) for output.
However, you can also provide your own output destination by invoking dbg.New with
a customization function:
import (
"bytes"
Dbg "github.com/robertkrimen/dbg"
"os"
)
# dbg to os.Stderr
dbg, dbgf := Dbg.New(func(dbgr *Dbgr) {
dbgr.SetOutput(os.Stderr)
})
# A slightly contrived example:
var buffer bytes.Buffer
dbg, dbgf := New(func(dbgr *Dbgr) {
dbgr.SetOutput(&buffer)
})
*/
package dbg
import (
"bytes"
"fmt"
"io"
"log"
"os"
"regexp"
"runtime"
"strings"
"unicode"
)
type _frmt struct {
ctl string
format string
operandCount int
panic bool
fatal bool
check bool
}
var (
ctlTest = regexp.MustCompile(`^\s*%/`)
ctlScan = regexp.MustCompile(`%?/(panic|fatal|check)(?:\s|$)`)
)
func operandCount(format string) int {
count := 0
end := len(format)
for at := 0; at < end; {
for at < end && format[at] != '%' {
at++
}
at++
if at < end {
if format[at] != '%' && format[at] != '@' {
count++
}
at++
}
}
return count
}
func parseFormat(format string) (frmt _frmt) {
if ctlTest.MatchString(format) {
format = strings.TrimLeftFunc(format, unicode.IsSpace)
index := strings.Index(format, "//")
if index != -1 {
frmt.ctl = format[0:index]
format = format[index+2:] // Skip the second slash via +2 (instead of +1)
} else {
frmt.ctl = format
format = ""
}
for _, tmp := range ctlScan.FindAllStringSubmatch(frmt.ctl, -1) {
for _, value := range tmp[1:] {
switch value {
case "panic":
frmt.panic = true
case "fatal":
frmt.fatal = true
case "check":
frmt.check = true
}
}
}
}
frmt.format = format
frmt.operandCount = operandCount(format)
return
}
type Dbgr struct {
emit _emit
}
type DbgFunction func(values ...interface{})
func NewDbgr() *Dbgr {
self := &Dbgr{}
return self
}
/*
New will create and return a pair of debugging functions. You can customize where
they output to by passing in an (optional) customization function:
import (
Dbg "github.com/robertkrimen/dbg"
"os"
)
# dbg to os.Stderr
dbg, dbgf := Dbg.New(func(dbgr *Dbgr) {
dbgr.SetOutput(os.Stderr)
})
*/
func New(options ...interface{}) (dbg DbgFunction, dbgf DbgFunction) {
dbgr := NewDbgr()
if len(options) > 0 {
if fn, ok := options[0].(func(*Dbgr)); ok {
fn(dbgr)
}
}
return dbgr.DbgDbgf()
}
func (self Dbgr) Dbg(values ...interface{}) {
self.getEmit().emit(_frmt{}, "", values...)
}
func (self Dbgr) Dbgf(values ...interface{}) {
self.dbgf(values...)
}
func (self Dbgr) DbgDbgf() (dbg DbgFunction, dbgf DbgFunction) {
dbg = func(vl ...interface{}) {
self.Dbg(vl...)
}
dbgf = func(vl ...interface{}) {
self.dbgf(vl...)
}
return dbg, dbgf // Redundant, but...
}
func (self Dbgr) dbgf(values ...interface{}) {
var frmt _frmt
if len(values) > 0 {
tmp := fmt.Sprint(values[0])
frmt = parseFormat(tmp)
values = values[1:]
}
buffer_f := bytes.Buffer{}
format := frmt.format
end := len(format)
for at := 0; at < end; {
last := at
for at < end && format[at] != '%' {
at++
}
if at > last {
buffer_f.WriteString(format[last:at])
}
if at >= end {
break
}
// format[at] == '%'
at++
// format[at] == ?
if format[at] == '@' {
depth := 2
pc, _, _, _ := runtime.Caller(depth)
name := runtime.FuncForPC(pc).Name()
buffer_f.WriteString(name)
} else {
buffer_f.WriteString(format[at-1 : at+1])
}
at++
}
//values_f := append([]interface{}{}, values[0:frmt.operandCount]...)
values_f := values[0:frmt.operandCount]
values_dbg := values[frmt.operandCount:]
if len(values_dbg) > 0 {
// Adjust frmt.format:
// (%v instead of %s because: frmt.check)
{
tmp := format
if len(tmp) > 0 {
if unicode.IsSpace(rune(tmp[len(tmp)-1])) {
buffer_f.WriteString("%v")
} else {
buffer_f.WriteString(" %v")
}
} else if frmt.check {
// Performing a check, so no output
} else {
buffer_f.WriteString("%v")
}
}
// Adjust values_f:
if !frmt.check {
tmp := []string{}
for _, value := range values_dbg {
tmp = append(tmp, fmt.Sprintf("%v", value))
}
// First, make a copy of values_f, so we avoid overwriting values_dbg when appending
values_f = append([]interface{}{}, values_f...)
values_f = append(values_f, strings.Join(tmp, " "))
}
}
format = buffer_f.String()
if frmt.check {
// We do not actually emit to the log, but panic if
// a non-nil value is detected (e.g. a non-nil error)
for _, value := range values_dbg {
if value != nil {
if format == "" {
panic(value)
} else {
panic(fmt.Sprintf(format, append(values_f, value)...))
}
}
}
} else {
self.getEmit().emit(frmt, format, values_f...)
}
}
// Idiot-proof &Dbgr{}, etc.
func (self *Dbgr) getEmit() _emit {
if self.emit == nil {
self.emit = standardEmit()
}
return self.emit
}
// SetOutput will accept the following as a destination for output:
//
// *log.Logger Print*/Panic*/Fatal* of the logger
// io.Writer -
// nil Reset to the default output (os.Stderr)
// "log" Print*/Panic*/Fatal* via the "log" package
//
func (self *Dbgr) SetOutput(output interface{}) {
if output == nil {
self.emit = standardEmit()
return
}
switch output := output.(type) {
case *log.Logger:
self.emit = _emitLogger{
logger: output,
}
return
case io.Writer:
self.emit = _emitWriter{
writer: output,
}
return
case string:
if output == "log" {
self.emit = _emitLog{}
return
}
}
panic(output)
}
// ======== //
// = emit = //
// ======== //
func standardEmit() _emit {
return _emitWriter{
writer: os.Stderr,
}
}
func ln(tmp string) string {
length := len(tmp)
if length > 0 && tmp[length-1] != '\n' {
return tmp + "\n"
}
return tmp
}
type _emit interface {
emit(_frmt, string, ...interface{})
}
type _emitWriter struct {
writer io.Writer
}
func (self _emitWriter) emit(frmt _frmt, format string, values ...interface{}) {
if format == "" {
fmt.Fprintln(self.writer, values...)
} else {
if frmt.panic {
panic(fmt.Sprintf(format, values...))
}
fmt.Fprintf(self.writer, ln(format), values...)
if frmt.fatal {
os.Exit(1)
}
}
}
type _emitLogger struct {
logger *log.Logger
}
func (self _emitLogger) emit(frmt _frmt, format string, values ...interface{}) {
if format == "" {
self.logger.Println(values...)
} else {
if frmt.panic {
self.logger.Panicf(format, values...)
} else if frmt.fatal {
self.logger.Fatalf(format, values...)
} else {
self.logger.Printf(format, values...)
}
}
}
type _emitLog struct {
}
func (self _emitLog) emit(frmt _frmt, format string, values ...interface{}) {
if format == "" {
log.Println(values...)
} else {
if frmt.panic {
log.Panicf(format, values...)
} else if frmt.fatal {
log.Fatalf(format, values...)
} else {
log.Printf(format, values...)
}
}
}

View file

@ -1,280 +0,0 @@
package otto
import (
"fmt"
)
// _environment
type _environment interface {
HasBinding(string) bool
CreateMutableBinding(string, bool)
SetMutableBinding(string, Value, bool)
// SetMutableBinding with Lazy CreateMutableBinding(..., true)
SetValue(string, Value, bool)
GetBindingValue(string, bool) Value
GetValue(string, bool) Value // GetBindingValue
DeleteBinding(string) bool
ImplicitThisValue() *_object
Outer() _environment
newReference(string, bool) _reference
clone(clone *_clone) _environment
runtimeOf() *_runtime
}
// _functionEnvironment
type _functionEnvironment struct {
_declarativeEnvironment
arguments *_object
indexOfArgumentName map[string]string
}
func (runtime *_runtime) newFunctionEnvironment(outer _environment) *_functionEnvironment {
return &_functionEnvironment{
_declarativeEnvironment: _declarativeEnvironment{
runtime: runtime,
outer: outer,
property: map[string]_declarativeProperty{},
},
}
}
func (self0 _functionEnvironment) clone(clone *_clone) _environment {
return &_functionEnvironment{
*(self0._declarativeEnvironment.clone(clone).(*_declarativeEnvironment)),
clone.object(self0.arguments),
self0.indexOfArgumentName,
}
}
func (self _functionEnvironment) runtimeOf() *_runtime {
return self._declarativeEnvironment.runtimeOf()
}
// _objectEnvironment
type _objectEnvironment struct {
runtime *_runtime
outer _environment
Object *_object
ProvideThis bool
}
func (self *_objectEnvironment) runtimeOf() *_runtime {
return self.runtime
}
func (runtime *_runtime) newObjectEnvironment(object *_object, outer _environment) *_objectEnvironment {
if object == nil {
object = runtime.newBaseObject()
object.class = "environment"
}
return &_objectEnvironment{
runtime: runtime,
outer: outer,
Object: object,
}
}
func (self0 *_objectEnvironment) clone(clone *_clone) _environment {
self1, exists := clone.objectEnvironment(self0)
if exists {
return self1
}
*self1 = _objectEnvironment{
clone.runtime,
clone.environment(self0.outer),
clone.object(self0.Object),
self0.ProvideThis,
}
return self1
}
func (self *_objectEnvironment) HasBinding(name string) bool {
return self.Object.hasProperty(name)
}
func (self *_objectEnvironment) CreateMutableBinding(name string, deletable bool) {
if self.Object.hasProperty(name) {
panic(hereBeDragons())
}
mode := _propertyMode(0111)
if !deletable {
mode = _propertyMode(0110)
}
// TODO False?
self.Object.defineProperty(name, UndefinedValue(), mode, false)
}
func (self *_objectEnvironment) SetMutableBinding(name string, value Value, strict bool) {
self.Object.put(name, value, strict)
}
func (self *_objectEnvironment) SetValue(name string, value Value, throw bool) {
if !self.HasBinding(name) {
self.CreateMutableBinding(name, true) // Configurable by default
}
self.SetMutableBinding(name, value, throw)
}
func (self *_objectEnvironment) GetBindingValue(name string, strict bool) Value {
if self.Object.hasProperty(name) {
return self.Object.get(name)
}
if strict {
panic(newReferenceError("Not Defined", name))
}
return UndefinedValue()
}
func (self *_objectEnvironment) GetValue(name string, throw bool) Value {
return self.GetBindingValue(name, throw)
}
func (self *_objectEnvironment) DeleteBinding(name string) bool {
return self.Object.delete(name, false)
}
func (self *_objectEnvironment) ImplicitThisValue() *_object {
if self.ProvideThis {
return self.Object
}
return nil
}
func (self *_objectEnvironment) Outer() _environment {
return self.outer
}
func (self *_objectEnvironment) newReference(name string, strict bool) _reference {
return newPropertyReference(self.Object, name, strict)
}
// _declarativeEnvironment
func (runtime *_runtime) newDeclarativeEnvironment(outer _environment) *_declarativeEnvironment {
return &_declarativeEnvironment{
runtime: runtime,
outer: outer,
property: map[string]_declarativeProperty{},
}
}
func (self0 *_declarativeEnvironment) clone(clone *_clone) _environment {
self1, exists := clone.declarativeEnvironment(self0)
if exists {
return self1
}
property := make(map[string]_declarativeProperty, len(self0.property))
for index, value := range self0.property {
property[index] = clone.declarativeProperty(value)
}
*self1 = _declarativeEnvironment{
clone.runtime,
clone.environment(self0.outer),
property,
}
return self1
}
type _declarativeProperty struct {
value Value
mutable bool
deletable bool
readable bool
}
type _declarativeEnvironment struct {
runtime *_runtime
outer _environment
property map[string]_declarativeProperty
}
func (self *_declarativeEnvironment) HasBinding(name string) bool {
_, exists := self.property[name]
return exists
}
func (self *_declarativeEnvironment) runtimeOf() *_runtime {
return self.runtime
}
func (self *_declarativeEnvironment) CreateMutableBinding(name string, deletable bool) {
_, exists := self.property[name]
if exists {
panic(fmt.Errorf("CreateMutableBinding: %s: already exists", name))
}
self.property[name] = _declarativeProperty{
value: UndefinedValue(),
mutable: true,
deletable: deletable,
readable: false,
}
}
func (self *_declarativeEnvironment) SetMutableBinding(name string, value Value, strict bool) {
property, exists := self.property[name]
if !exists {
panic(fmt.Errorf("SetMutableBinding: %s: missing", name))
}
if property.mutable {
property.value = value
self.property[name] = property
} else {
typeErrorResult(strict)
}
}
func (self *_declarativeEnvironment) SetValue(name string, value Value, throw bool) {
if !self.HasBinding(name) {
self.CreateMutableBinding(name, false) // NOT deletable by default
}
self.SetMutableBinding(name, value, throw)
}
func (self *_declarativeEnvironment) GetBindingValue(name string, strict bool) Value {
property, exists := self.property[name]
if !exists {
panic(fmt.Errorf("GetBindingValue: %s: missing", name))
}
if !property.mutable && !property.readable {
if strict {
panic(newTypeError())
}
return UndefinedValue()
}
return property.value
}
func (self *_declarativeEnvironment) GetValue(name string, throw bool) Value {
return self.GetBindingValue(name, throw)
}
func (self *_declarativeEnvironment) DeleteBinding(name string) bool {
property, exists := self.property[name]
if !exists {
return true
}
if !property.deletable {
return false
}
delete(self.property, name)
return true
}
func (self *_declarativeEnvironment) ImplicitThisValue() *_object {
return nil
}
func (self *_declarativeEnvironment) Outer() _environment {
return self.outer
}
func (self *_declarativeEnvironment) newReference(name string, strict bool) _reference {
return newEnvironmentReference(self, name, strict, nil)
}

View file

@ -1,152 +0,0 @@
package otto
import (
"errors"
"fmt"
"github.com/robertkrimen/otto/ast"
)
type _exception struct {
value interface{}
}
func newException(value interface{}) *_exception {
return &_exception{
value: value,
}
}
func (self *_exception) eject() interface{} {
value := self.value
self.value = nil // Prevent Go from holding on to the value, whatever it is
return value
}
type _error struct {
Name string
Message string
Line int // Hackish -- line where the error/exception occurred
}
var messageDetail map[string]string = map[string]string{
"notDefined": "%v is not defined",
}
func messageFromDescription(description string, argumentList ...interface{}) string {
message := messageDetail[description]
if message == "" {
message = description
}
message = fmt.Sprintf(message, argumentList...)
return message
}
func (self _error) MessageValue() Value {
if self.Message == "" {
return UndefinedValue()
}
return toValue_string(self.Message)
}
func (self _error) String() string {
if len(self.Name) == 0 {
return self.Message
}
if len(self.Message) == 0 {
return self.Name
}
return fmt.Sprintf("%s: %s", self.Name, self.Message)
}
func newError(name string, argumentList ...interface{}) _error {
description := ""
var node ast.Node = nil
length := len(argumentList)
if length > 0 {
if node, _ = argumentList[length-1].(ast.Node); node != nil || argumentList[length-1] == nil {
argumentList = argumentList[0 : length-1]
length -= 1
}
if length > 0 {
description, argumentList = argumentList[0].(string), argumentList[1:]
}
}
return _error{
Name: name,
Message: messageFromDescription(description, argumentList...),
Line: -1,
}
//error := _error{
// Name: name,
// Message: messageFromDescription(description, argumentList...),
// Line: -1,
//}
//if node != nil {
// error.Line = ast.position()
//}
//return error
}
func newReferenceError(argumentList ...interface{}) _error {
return newError("ReferenceError", argumentList...)
}
func newTypeError(argumentList ...interface{}) _error {
return newError("TypeError", argumentList...)
}
func newRangeError(argumentList ...interface{}) _error {
return newError("RangeError", argumentList...)
}
func newSyntaxError(argumentList ...interface{}) _error {
return newError("SyntaxError", argumentList...)
}
func newURIError(argumentList ...interface{}) _error {
return newError("URIError", argumentList...)
}
func typeErrorResult(throw bool) bool {
if throw {
panic(newTypeError())
}
return false
}
func catchPanic(function func()) (err error) {
// FIXME
defer func() {
if caught := recover(); caught != nil {
if exception, ok := caught.(*_exception); ok {
caught = exception.eject()
}
switch caught := caught.(type) {
//case *_syntaxError:
// err = errors.New(fmt.Sprintf("%s (line %d)", caught.String(), caught.Line+0))
// return
case _error:
if caught.Line == -1 {
err = errors.New(caught.String())
} else {
// We're 0-based (for now), hence the + 1
err = errors.New(fmt.Sprintf("%s (line %d)", caught.String(), caught.Line+1))
}
return
case Value:
err = errors.New(toString(caught))
return
//case string:
// if strings.HasPrefix(caught, "SyntaxError:") {
// err = errors.New(caught)
// return
// }
}
panic(caught)
}
}()
function()
return nil
}

View file

@ -1,62 +0,0 @@
package otto
import (
"testing"
)
func TestError(t *testing.T) {
tt(t, func() {
test, _ := test()
test(`
[ Error.prototype.name, Error.prototype.message, Error.prototype.hasOwnProperty("message") ];
`, "Error,,true")
})
}
func TestError_instanceof(t *testing.T) {
tt(t, func() {
test, _ := test()
test(`(new TypeError()) instanceof Error`, true)
})
}
func TestPanicValue(t *testing.T) {
tt(t, func() {
test, vm := test()
vm.Set("abc", func(call FunctionCall) Value {
value, err := call.Otto.Run(`({ def: 3.14159 })`)
is(err, nil)
panic(value)
})
test(`
try {
abc();
}
catch (err) {
error = err;
}
[ error instanceof Error, error.message, error.def ];
`, "false,,3.14159")
})
}
func Test_catchPanic(t *testing.T) {
tt(t, func() {
vm := New()
_, err := vm.Run(`
A syntax error that
does not define
var;
abc;
`)
is(err, "!=", nil)
_, err = vm.Call(`abc.def`, nil)
is(err, "!=", nil)
})
}

View file

@ -1,40 +0,0 @@
package otto
type _executionContext struct {
LexicalEnvironment _environment
VariableEnvironment _environment
this *_object
eval bool // Replace this with kind?
}
func newExecutionContext(lexical _environment, variable _environment, this *_object) *_executionContext {
return &_executionContext{
LexicalEnvironment: lexical,
VariableEnvironment: variable,
this: this,
}
}
func (self *_executionContext) getValue(name string) Value {
strict := false
return self.LexicalEnvironment.GetValue(name, strict)
}
func (self *_executionContext) setValue(name string, value Value, throw bool) {
self.LexicalEnvironment.SetValue(name, value, throw)
}
func (self *_executionContext) newLexicalEnvironment(object *_object) (_environment, *_objectEnvironment) {
// Get runtime from the object (for now)
runtime := object.runtime
previousLexical := self.LexicalEnvironment
newLexical := runtime.newObjectEnvironment(object, self.LexicalEnvironment)
self.LexicalEnvironment = newLexical
return previousLexical, newLexical
}
func (self *_executionContext) newDeclarativeEnvironment(runtime *_runtime) _environment {
previousLexical := self.LexicalEnvironment
self.LexicalEnvironment = runtime.newDeclarativeEnvironment(self.LexicalEnvironment)
return previousLexical
}

View file

@ -1,72 +0,0 @@
# file
--
import "github.com/robertkrimen/otto/file"
Package file encapsulates the file abstractions used by the ast & parser.
## Usage
#### type FileSet
```go
type FileSet struct {
}
```
A FileSet represents a set of source files.
#### func (*FileSet) AddFile
```go
func (self *FileSet) AddFile(filename, src string) int
```
AddFile adds a new file with the given filename and src.
This an internal method, but exported for cross-package use.
#### func (*FileSet) Position
```go
func (self *FileSet) Position(idx Idx) *Position
```
Position converts an Idx in the FileSet into a Position.
#### type Idx
```go
type Idx int
```
Idx is a compact encoding of a source position within a file set. It can be
converted into a Position for a more convenient, but much larger,
representation.
#### type Position
```go
type Position struct {
Filename string // The filename where the error occurred, if any
Offset int // The src offset
Line int // The line number, starting at 1
Column int // The column number, starting at 1 (The character count)
}
```
Position describes an arbitrary source position including the filename, line,
and column location.
#### func (*Position) String
```go
func (self *Position) String() string
```
String returns a string in one of several forms:
file:line:column A valid position with filename
line:column A valid position without filename
file An invalid position with filename
- An invalid position without filename
--
**godocdown** http://github.com/robertkrimen/godocdown

View file

@ -1,106 +0,0 @@
// Package file encapsulates the file abstractions used by the ast & parser.
//
package file
import (
"fmt"
"strings"
)
// Idx is a compact encoding of a source position within a file set.
// It can be converted into a Position for a more convenient, but much
// larger, representation.
type Idx int
// Position describes an arbitrary source position
// including the filename, line, and column location.
type Position struct {
Filename string // The filename where the error occurred, if any
Offset int // The src offset
Line int // The line number, starting at 1
Column int // The column number, starting at 1 (The character count)
}
// A Position is valid if the line number is > 0.
func (self *Position) isValid() bool {
return self.Line > 0
}
// String returns a string in one of several forms:
//
// file:line:column A valid position with filename
// line:column A valid position without filename
// file An invalid position with filename
// - An invalid position without filename
//
func (self *Position) String() string {
str := self.Filename
if self.isValid() {
if str != "" {
str += ":"
}
str += fmt.Sprintf("%d:%d", self.Line, self.Column)
}
if str == "" {
str = "-"
}
return str
}
// FileSet
// A FileSet represents a set of source files.
type FileSet struct {
files []*_file
last *_file
}
// AddFile adds a new file with the given filename and src.
//
// This an internal method, but exported for cross-package use.
func (self *FileSet) AddFile(filename, src string) int {
base := self.nextBase()
file := &_file{
filename: filename,
src: src,
base: base,
}
self.files = append(self.files, file)
self.last = file
return base
}
func (self *FileSet) nextBase() int {
if self.last == nil {
return 1
}
return self.last.base + len(self.last.src) + 1
}
// Position converts an Idx in the FileSet into a Position.
func (self *FileSet) Position(idx Idx) *Position {
position := &Position{}
for _, file := range self.files {
if idx <= Idx(file.base+len(file.src)) {
offset := int(idx) - file.base
src := file.src[:offset]
position.Filename = file.filename
position.Offset = offset
position.Line = 1 + strings.Count(src, "\n")
if index := strings.LastIndex(src, "\n"); index >= 0 {
position.Column = offset - index
} else {
position.Column = 1 + len(src)
}
}
}
return position
}
type _file struct {
filename string
src string
base int // This will always be 1 or greater
}

View file

@ -1,4 +0,0 @@
.PHONY: test
test:
go test

View file

@ -1,190 +0,0 @@
# parser
--
import "github.com/robertkrimen/otto/parser"
Package parser implements a parser for JavaScript.
import (
"github.com/robertkrimen/otto/parser"
)
Parse and return an AST
filename := "" // A filename is optional
src := `
// Sample xyzzy example
(function(){
if (3.14159 > 0) {
console.log("Hello, World.");
return;
}
var xyzzy = NaN;
console.log("Nothing happens.");
return xyzzy;
})();
`
// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, filename, src, 0)
### Warning
The parser and AST interfaces are still works-in-progress (particularly where
node types are concerned) and may change in the future.
## Usage
#### func ParseFile
```go
func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error)
```
ParseFile parses the source code of a single JavaScript/ECMAScript source file
and returns the corresponding ast.Program node.
If fileSet == nil, ParseFile parses source without a FileSet. If fileSet != nil,
ParseFile first adds filename and src to fileSet.
The filename argument is optional and is used for labelling errors, etc.
src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST
always be in UTF-8.
// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0)
#### func ParseFunction
```go
func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error)
```
ParseFunction parses a given parameter list and body as a function and returns
the corresponding ast.FunctionLiteral node.
The parameter list, if any, should be a comma-separated list of identifiers.
#### func ReadSource
```go
func ReadSource(filename string, src interface{}) ([]byte, error)
```
#### func TransformRegExp
```go
func TransformRegExp(pattern string) (string, error)
```
TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern.
re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or
backreference (\1, \2, ...) will cause an error.
re2 (Go) has a different definition for \s: [\t\n\f\r ]. The JavaScript
definition, on the other hand, also includes \v, Unicode "Separator, Space",
etc.
If the pattern is invalid (not valid even in JavaScript), then this function
returns the empty string and an error.
If the pattern is valid, but incompatible (contains a lookahead or
backreference), then this function returns the transformation (a non-empty
string) AND an error.
#### type Error
```go
type Error struct {
Position file.Position
Message string
}
```
An Error represents a parsing error. It includes the position where the error
occurred and a message/description.
#### func (Error) Error
```go
func (self Error) Error() string
```
#### type ErrorList
```go
type ErrorList []*Error
```
ErrorList is a list of *Errors.
#### func (*ErrorList) Add
```go
func (self *ErrorList) Add(position file.Position, msg string)
```
Add adds an Error with given position and message to an ErrorList.
#### func (ErrorList) Err
```go
func (self ErrorList) Err() error
```
Err returns an error equivalent to this ErrorList. If the list is empty, Err
returns nil.
#### func (ErrorList) Error
```go
func (self ErrorList) Error() string
```
Error implements the Error interface.
#### func (ErrorList) Len
```go
func (self ErrorList) Len() int
```
#### func (ErrorList) Less
```go
func (self ErrorList) Less(i, j int) bool
```
#### func (*ErrorList) Reset
```go
func (self *ErrorList) Reset()
```
Reset resets an ErrorList to no errors.
#### func (ErrorList) Sort
```go
func (self ErrorList) Sort()
```
#### func (ErrorList) Swap
```go
func (self ErrorList) Swap(i, j int)
```
#### type Mode
```go
type Mode uint
```
A Mode value is a set of flags (or 0). They control optional parser
functionality.
```go
const (
IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
)
```
--
**godocdown** http://github.com/robertkrimen/godocdown

View file

@ -1,9 +0,0 @@
// This file was AUTOMATICALLY GENERATED by dbg-import (smuggol) for github.com/robertkrimen/dbg
package parser
import (
Dbg "github.com/robertkrimen/otto/dbg"
)
var dbg, dbgf = Dbg.New()

View file

@ -1,175 +0,0 @@
package parser
import (
"fmt"
"sort"
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
const (
err_UnexpectedToken = "Unexpected token %v"
err_UnexpectedEndOfInput = "Unexpected end of input"
err_UnexpectedEscape = "Unexpected escape"
)
// UnexpectedNumber: 'Unexpected number',
// UnexpectedString: 'Unexpected string',
// UnexpectedIdentifier: 'Unexpected identifier',
// UnexpectedReserved: 'Unexpected reserved word',
// NewlineAfterThrow: 'Illegal newline after throw',
// InvalidRegExp: 'Invalid regular expression',
// UnterminatedRegExp: 'Invalid regular expression: missing /',
// InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
// InvalidLHSInForIn: 'Invalid left-hand side in for-in',
// MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
// NoCatchOrFinally: 'Missing catch or finally after try',
// UnknownLabel: 'Undefined label \'%0\'',
// Redeclaration: '%0 \'%1\' has already been declared',
// IllegalContinue: 'Illegal continue statement',
// IllegalBreak: 'Illegal break statement',
// IllegalReturn: 'Illegal return statement',
// StrictModeWith: 'Strict mode code may not include a with statement',
// StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
// StrictVarName: 'Variable name may not be eval or arguments in strict mode',
// StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
// StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
// StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
// StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
// StrictDelete: 'Delete of an unqualified identifier in strict mode.',
// StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
// AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
// AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
// StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
// StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
// StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
// StrictReservedWord: 'Use of future reserved word in strict mode'
// A SyntaxError is a description of an ECMAScript syntax error.
// An Error represents a parsing error. It includes the position where the error occurred and a message/description.
type Error struct {
Position file.Position
Message string
}
// FXIME Should this be "SyntaxError"?
func (self Error) Error() string {
filename := self.Position.Filename
if filename == "" {
filename = "(anonymous)"
}
return fmt.Sprintf("%s: Line %d:%d %s",
filename,
self.Position.Line,
self.Position.Column,
self.Message,
)
}
func (self *_parser) error(place interface{}, msg string, msgValues ...interface{}) *Error {
idx := file.Idx(0)
switch place := place.(type) {
case int:
idx = self.idxOf(place)
case file.Idx:
if place == 0 {
idx = self.idxOf(self.chrOffset)
} else {
idx = place
}
default:
panic(fmt.Errorf("error(%T, ...)", place))
}
position := self.position(idx)
msg = fmt.Sprintf(msg, msgValues...)
self.errors.Add(position, msg)
return self.errors[len(self.errors)-1]
}
func (self *_parser) errorUnexpected(idx file.Idx, chr rune) error {
if chr == -1 {
return self.error(idx, err_UnexpectedEndOfInput)
}
return self.error(idx, err_UnexpectedToken, token.ILLEGAL)
}
func (self *_parser) errorUnexpectedToken(tkn token.Token) error {
switch tkn {
case token.EOF:
return self.error(file.Idx(0), err_UnexpectedEndOfInput)
}
value := tkn.String()
switch tkn {
case token.BOOLEAN, token.NULL:
value = self.literal
case token.IDENTIFIER:
return self.error(self.idx, "Unexpected identifier")
case token.KEYWORD:
// TODO Might be a future reserved word
return self.error(self.idx, "Unexpected reserved word")
case token.NUMBER:
return self.error(self.idx, "Unexpected number")
case token.STRING:
return self.error(self.idx, "Unexpected string")
}
return self.error(self.idx, err_UnexpectedToken, value)
}
// ErrorList is a list of *Errors.
//
type ErrorList []*Error
// Add adds an Error with given position and message to an ErrorList.
func (self *ErrorList) Add(position file.Position, msg string) {
*self = append(*self, &Error{position, msg})
}
// Reset resets an ErrorList to no errors.
func (self *ErrorList) Reset() { *self = (*self)[0:0] }
func (self ErrorList) Len() int { return len(self) }
func (self ErrorList) Swap(i, j int) { self[i], self[j] = self[j], self[i] }
func (self ErrorList) Less(i, j int) bool {
x := &self[i].Position
y := &self[j].Position
if x.Filename < y.Filename {
return true
}
if x.Filename == y.Filename {
if x.Line < y.Line {
return true
}
if x.Line == y.Line {
return x.Column < y.Column
}
}
return false
}
func (self ErrorList) Sort() {
sort.Sort(self)
}
// Error implements the Error interface.
func (self ErrorList) Error() string {
switch len(self) {
case 0:
return "no errors"
case 1:
return self[0].Error()
}
return fmt.Sprintf("%s (and %d more errors)", self[0].Error(), len(self)-1)
}
// Err returns an error equivalent to this ErrorList.
// If the list is empty, Err returns nil.
func (self ErrorList) Err() error {
if len(self) == 0 {
return nil
}
return self
}

View file

@ -1,815 +0,0 @@
package parser
import (
"regexp"
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
func (self *_parser) parseIdentifier() *ast.Identifier {
literal := self.literal
idx := self.idx
self.next()
return &ast.Identifier{
Name: literal,
Idx: idx,
}
}
func (self *_parser) parsePrimaryExpression() ast.Expression {
literal := self.literal
idx := self.idx
switch self.token {
case token.IDENTIFIER:
self.next()
if len(literal) > 1 {
tkn, strict := token.IsKeyword(literal)
if tkn == token.KEYWORD {
if !strict {
self.error(idx, "Unexpected reserved word")
}
}
}
return &ast.Identifier{
Name: literal,
Idx: idx,
}
case token.NULL:
self.next()
return &ast.NullLiteral{
Idx: idx,
Literal: literal,
}
case token.BOOLEAN:
self.next()
value := false
switch literal {
case "true":
value = true
case "false":
value = false
default:
self.error(idx, "Illegal boolean literal")
}
return &ast.BooleanLiteral{
Idx: idx,
Literal: literal,
Value: value,
}
case token.STRING:
self.next()
value, err := parseStringLiteral(literal[1 : len(literal)-1])
if err != nil {
self.error(idx, err.Error())
}
return &ast.StringLiteral{
Idx: idx,
Literal: literal,
Value: value,
}
case token.NUMBER:
self.next()
value, err := parseNumberLiteral(literal)
if err != nil {
self.error(idx, err.Error())
value = 0
}
return &ast.NumberLiteral{
Idx: idx,
Literal: literal,
Value: value,
}
case token.SLASH, token.QUOTIENT_ASSIGN:
return self.parseRegExpLiteral()
case token.LEFT_BRACE:
return self.parseObjectLiteral()
case token.LEFT_BRACKET:
return self.parseArrayLiteral()
case token.LEFT_PARENTHESIS:
self.expect(token.LEFT_PARENTHESIS)
expression := self.parseExpression()
self.expect(token.RIGHT_PARENTHESIS)
return expression
case token.THIS:
self.next()
return &ast.ThisExpression{
Idx: idx,
}
case token.FUNCTION:
return self.parseFunction(false)
}
self.errorUnexpectedToken(self.token)
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
func (self *_parser) parseRegExpLiteral() *ast.RegExpLiteral {
offset := self.chrOffset - 1 // Opening slash already gotten
if self.token == token.QUOTIENT_ASSIGN {
offset -= 1 // =
}
idx := self.idxOf(offset)
pattern, err := self.scanString(offset)
endOffset := self.chrOffset
self.next()
if err == nil {
pattern = pattern[1 : len(pattern)-1]
}
flags := ""
if self.token == token.IDENTIFIER { // gim
flags = self.literal
self.next()
endOffset = self.chrOffset - 1
}
var value string
// TODO 15.10
{
// Test during parsing that this is a valid regular expression
// Sorry, (?=) and (?!) are invalid (for now)
pattern, err := TransformRegExp(pattern)
if err != nil {
if pattern == "" || self.mode&IgnoreRegExpErrors == 0 {
self.error(idx, "Invalid regular expression: %s", err.Error())
}
} else {
_, err = regexp.Compile(pattern)
if err != nil {
// We should not get here, ParseRegExp should catch any errors
self.error(idx, "Invalid regular expression: %s", err.Error()[22:]) // Skip redundant "parse regexp error"
} else {
value = pattern
}
}
}
literal := self.str[offset:endOffset]
return &ast.RegExpLiteral{
Idx: idx,
Literal: literal,
Pattern: pattern,
Flags: flags,
Value: value,
}
}
func (self *_parser) parseVariableDeclaration(declarationList *[]*ast.VariableExpression) ast.Expression {
if self.token != token.IDENTIFIER {
idx := self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
literal := self.literal
idx := self.idx
self.next()
node := &ast.VariableExpression{
Name: literal,
Idx: idx,
}
if declarationList != nil {
*declarationList = append(*declarationList, node)
}
if self.token == token.ASSIGN {
self.next()
node.Initializer = self.parseAssignmentExpression()
}
return node
}
func (self *_parser) parseVariableDeclarationList(var_ file.Idx) []ast.Expression {
var declarationList []*ast.VariableExpression // Avoid bad expressions
var list []ast.Expression
for {
list = append(list, self.parseVariableDeclaration(&declarationList))
if self.token != token.COMMA {
break
}
self.next()
}
self.scope.declare(&ast.VariableDeclaration{
Var: var_,
List: declarationList,
})
return list
}
func (self *_parser) parseObjectPropertyKey() (string, string) {
idx, tkn, literal := self.idx, self.token, self.literal
value := ""
self.next()
switch tkn {
case token.IDENTIFIER:
value = literal
case token.NUMBER:
var err error
_, err = parseNumberLiteral(literal)
if err != nil {
self.error(idx, err.Error())
} else {
value = literal
}
case token.STRING:
var err error
value, err = parseStringLiteral(literal[1 : len(literal)-1])
if err != nil {
self.error(idx, err.Error())
}
default:
// null, false, class, etc.
if matchIdentifier.MatchString(literal) {
value = literal
}
}
return literal, value
}
func (self *_parser) parseObjectProperty() ast.Property {
literal, value := self.parseObjectPropertyKey()
if literal == "get" && self.token != token.COLON {
idx := self.idx
_, value := self.parseObjectPropertyKey()
parameterList := self.parseFunctionParameterList()
node := &ast.FunctionLiteral{
Function: idx,
ParameterList: parameterList,
}
self.parseFunctionBlock(node)
return ast.Property{
Key: value,
Kind: "get",
Value: node,
}
} else if literal == "set" && self.token != token.COLON {
idx := self.idx
_, value := self.parseObjectPropertyKey()
parameterList := self.parseFunctionParameterList()
node := &ast.FunctionLiteral{
Function: idx,
ParameterList: parameterList,
}
self.parseFunctionBlock(node)
return ast.Property{
Key: value,
Kind: "set",
Value: node,
}
}
self.expect(token.COLON)
return ast.Property{
Key: value,
Kind: "value",
Value: self.parseAssignmentExpression(),
}
}
func (self *_parser) parseObjectLiteral() ast.Expression {
var value []ast.Property
idx0 := self.expect(token.LEFT_BRACE)
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
property := self.parseObjectProperty()
value = append(value, property)
if self.token == token.COMMA {
self.next()
continue
}
}
idx1 := self.expect(token.RIGHT_BRACE)
return &ast.ObjectLiteral{
LeftBrace: idx0,
RightBrace: idx1,
Value: value,
}
}
func (self *_parser) parseArrayLiteral() ast.Expression {
idx0 := self.expect(token.LEFT_BRACKET)
var value []ast.Expression
for self.token != token.RIGHT_BRACKET && self.token != token.EOF {
if self.token == token.COMMA {
self.next()
value = append(value, nil)
continue
}
value = append(value, self.parseAssignmentExpression())
if self.token != token.RIGHT_BRACKET {
self.expect(token.COMMA)
}
}
idx1 := self.expect(token.RIGHT_BRACKET)
return &ast.ArrayLiteral{
LeftBracket: idx0,
RightBracket: idx1,
Value: value,
}
}
func (self *_parser) parseArgumentList() (argumentList []ast.Expression, idx0, idx1 file.Idx) {
idx0 = self.expect(token.LEFT_PARENTHESIS)
if self.token != token.RIGHT_PARENTHESIS {
for {
argumentList = append(argumentList, self.parseAssignmentExpression())
if self.token != token.COMMA {
break
}
self.next()
}
}
idx1 = self.expect(token.RIGHT_PARENTHESIS)
return
}
func (self *_parser) parseCallExpression(left ast.Expression) ast.Expression {
argumentList, idx0, idx1 := self.parseArgumentList()
return &ast.CallExpression{
Callee: left,
LeftParenthesis: idx0,
ArgumentList: argumentList,
RightParenthesis: idx1,
}
}
func (self *_parser) parseDotMember(left ast.Expression) ast.Expression {
period := self.expect(token.PERIOD)
literal := self.literal
idx := self.idx
if !matchIdentifier.MatchString(literal) {
self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadExpression{From: period, To: self.idx}
}
self.next()
return &ast.DotExpression{
Left: left,
Identifier: ast.Identifier{
Idx: idx,
Name: literal,
},
}
}
func (self *_parser) parseBracketMember(left ast.Expression) ast.Expression {
idx0 := self.expect(token.LEFT_BRACKET)
member := self.parseExpression()
idx1 := self.expect(token.RIGHT_BRACKET)
return &ast.BracketExpression{
LeftBracket: idx0,
Left: left,
Member: member,
RightBracket: idx1,
}
}
func (self *_parser) parseNewExpression() ast.Expression {
idx := self.expect(token.NEW)
callee := self.parseLeftHandSideExpression()
node := &ast.NewExpression{
New: idx,
Callee: callee,
}
if self.token == token.LEFT_PARENTHESIS {
argumentList, idx0, idx1 := self.parseArgumentList()
node.ArgumentList = argumentList
node.LeftParenthesis = idx0
node.RightParenthesis = idx1
}
return node
}
func (self *_parser) parseLeftHandSideExpression() ast.Expression {
var left ast.Expression
if self.token == token.NEW {
left = self.parseNewExpression()
} else {
left = self.parsePrimaryExpression()
}
for {
if self.token == token.PERIOD {
left = self.parseDotMember(left)
} else if self.token == token.LEFT_BRACE {
left = self.parseBracketMember(left)
} else {
break
}
}
return left
}
func (self *_parser) parseLeftHandSideExpressionAllowCall() ast.Expression {
allowIn := self.scope.allowIn
self.scope.allowIn = true
defer func() {
self.scope.allowIn = allowIn
}()
var left ast.Expression
if self.token == token.NEW {
left = self.parseNewExpression()
} else {
left = self.parsePrimaryExpression()
}
for {
if self.token == token.PERIOD {
left = self.parseDotMember(left)
} else if self.token == token.LEFT_BRACKET {
left = self.parseBracketMember(left)
} else if self.token == token.LEFT_PARENTHESIS {
left = self.parseCallExpression(left)
} else {
break
}
}
return left
}
func (self *_parser) parsePostfixExpression() ast.Expression {
operand := self.parseLeftHandSideExpressionAllowCall()
switch self.token {
case token.INCREMENT, token.DECREMENT:
// Make sure there is no line terminator here
if self.implicitSemicolon {
break
}
tkn := self.token
idx := self.idx
self.next()
switch operand.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
default:
self.error(idx, "Invalid left-hand side in assignment")
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
return &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: operand,
Postfix: true,
}
}
return operand
}
func (self *_parser) parseUnaryExpression() ast.Expression {
switch self.token {
case token.PLUS, token.MINUS, token.NOT, token.BITWISE_NOT:
fallthrough
case token.DELETE, token.VOID, token.TYPEOF:
tkn := self.token
idx := self.idx
self.next()
return &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: self.parseUnaryExpression(),
}
case token.INCREMENT, token.DECREMENT:
tkn := self.token
idx := self.idx
self.next()
operand := self.parseUnaryExpression()
switch operand.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
default:
self.error(idx, "Invalid left-hand side in assignment")
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
return &ast.UnaryExpression{
Operator: tkn,
Idx: idx,
Operand: operand,
}
}
return self.parsePostfixExpression()
}
func (self *_parser) parseMultiplicativeExpression() ast.Expression {
next := self.parseUnaryExpression
left := next()
for self.token == token.MULTIPLY || self.token == token.SLASH ||
self.token == token.REMAINDER {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseAdditiveExpression() ast.Expression {
next := self.parseMultiplicativeExpression
left := next()
for self.token == token.PLUS || self.token == token.MINUS {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseShiftExpression() ast.Expression {
next := self.parseAdditiveExpression
left := next()
for self.token == token.SHIFT_LEFT || self.token == token.SHIFT_RIGHT ||
self.token == token.UNSIGNED_SHIFT_RIGHT {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseRelationalExpression() ast.Expression {
next := self.parseShiftExpression
left := next()
allowIn := self.scope.allowIn
self.scope.allowIn = true
defer func() {
self.scope.allowIn = allowIn
}()
switch self.token {
case token.LESS, token.LESS_OR_EQUAL, token.GREATER, token.GREATER_OR_EQUAL:
tkn := self.token
self.next()
return &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: self.parseRelationalExpression(),
Comparison: true,
}
case token.INSTANCEOF:
tkn := self.token
self.next()
return &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: self.parseRelationalExpression(),
}
case token.IN:
if !allowIn {
return left
}
tkn := self.token
self.next()
return &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: self.parseRelationalExpression(),
}
}
return left
}
func (self *_parser) parseEqualityExpression() ast.Expression {
next := self.parseRelationalExpression
left := next()
for self.token == token.EQUAL || self.token == token.NOT_EQUAL ||
self.token == token.STRICT_EQUAL || self.token == token.STRICT_NOT_EQUAL {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
Comparison: true,
}
}
return left
}
func (self *_parser) parseBitwiseAndExpression() ast.Expression {
next := self.parseEqualityExpression
left := next()
for self.token == token.AND {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseBitwiseExclusiveOrExpression() ast.Expression {
next := self.parseBitwiseAndExpression
left := next()
for self.token == token.EXCLUSIVE_OR {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseBitwiseOrExpression() ast.Expression {
next := self.parseBitwiseExclusiveOrExpression
left := next()
for self.token == token.OR {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseLogicalAndExpression() ast.Expression {
next := self.parseBitwiseOrExpression
left := next()
for self.token == token.LOGICAL_AND {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseLogicalOrExpression() ast.Expression {
next := self.parseLogicalAndExpression
left := next()
for self.token == token.LOGICAL_OR {
tkn := self.token
self.next()
left = &ast.BinaryExpression{
Operator: tkn,
Left: left,
Right: next(),
}
}
return left
}
func (self *_parser) parseConditionlExpression() ast.Expression {
left := self.parseLogicalOrExpression()
if self.token == token.QUESTION_MARK {
self.next()
consequent := self.parseAssignmentExpression()
self.expect(token.COLON)
return &ast.ConditionalExpression{
Test: left,
Consequent: consequent,
Alternate: self.parseAssignmentExpression(),
}
}
return left
}
func (self *_parser) parseAssignmentExpression() ast.Expression {
left := self.parseConditionlExpression()
var operator token.Token
switch self.token {
case token.ASSIGN:
operator = self.token
case token.ADD_ASSIGN:
operator = token.PLUS
case token.SUBTRACT_ASSIGN:
operator = token.MINUS
case token.MULTIPLY_ASSIGN:
operator = token.MULTIPLY
case token.QUOTIENT_ASSIGN:
operator = token.SLASH
case token.REMAINDER_ASSIGN:
operator = token.REMAINDER
case token.AND_ASSIGN:
operator = token.AND
case token.AND_NOT_ASSIGN:
operator = token.AND_NOT
case token.OR_ASSIGN:
operator = token.OR
case token.EXCLUSIVE_OR_ASSIGN:
operator = token.EXCLUSIVE_OR
case token.SHIFT_LEFT_ASSIGN:
operator = token.SHIFT_LEFT
case token.SHIFT_RIGHT_ASSIGN:
operator = token.SHIFT_RIGHT
case token.UNSIGNED_SHIFT_RIGHT_ASSIGN:
operator = token.UNSIGNED_SHIFT_RIGHT
}
if operator != 0 {
idx := self.idx
self.next()
switch left.(type) {
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression:
default:
self.error(left.Idx0(), "Invalid left-hand side in assignment")
self.nextStatement()
return &ast.BadExpression{From: idx, To: self.idx}
}
return &ast.AssignExpression{
Left: left,
Operator: operator,
Right: self.parseAssignmentExpression(),
}
}
return left
}
func (self *_parser) parseExpression() ast.Expression {
next := self.parseAssignmentExpression
left := next()
if self.token == token.COMMA {
sequence := []ast.Expression{left}
for {
if self.token != token.COMMA {
break
}
self.next()
sequence = append(sequence, next())
}
return &ast.SequenceExpression{
Sequence: sequence,
}
}
return left
}

View file

@ -1,819 +0,0 @@
package parser
import (
"bytes"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"unicode"
"unicode/utf8"
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
type _chr struct {
value rune
width int
}
var matchIdentifier = regexp.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`)
func isDecimalDigit(chr rune) bool {
return '0' <= chr && chr <= '9'
}
func digitValue(chr rune) int {
switch {
case '0' <= chr && chr <= '9':
return int(chr - '0')
case 'a' <= chr && chr <= 'f':
return int(chr - 'a' + 10)
case 'A' <= chr && chr <= 'F':
return int(chr - 'A' + 10)
}
return 16 // Larger than any legal digit value
}
func isDigit(chr rune, base int) bool {
return digitValue(chr) < base
}
func isIdentifierStart(chr rune) bool {
return chr == '$' || chr == '_' || chr == '\\' ||
'a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z' ||
chr >= utf8.RuneSelf && unicode.IsLetter(chr)
}
func isIdentifierPart(chr rune) bool {
return chr == '$' || chr == '_' || chr == '\\' ||
'a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z' ||
'0' <= chr && chr <= '9' ||
chr >= utf8.RuneSelf && (unicode.IsLetter(chr) || unicode.IsDigit(chr))
}
func (self *_parser) scanIdentifier() (string, error) {
offset := self.chrOffset
parse := false
for isIdentifierPart(self.chr) {
if self.chr == '\\' {
distance := self.chrOffset - offset
self.read()
if self.chr != 'u' {
return "", fmt.Errorf("Invalid identifier escape character: %c (%s)", self.chr, string(self.chr))
}
parse = true
var value rune
for j := 0; j < 4; j++ {
self.read()
decimal, ok := hex2decimal(byte(self.chr))
if !ok {
return "", fmt.Errorf("Invalid identifier escape character: %c (%s)", self.chr, string(self.chr))
}
value = value<<4 | decimal
}
if value == '\\' {
return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value))
} else if distance == 0 {
if !isIdentifierStart(value) {
return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value))
}
} else if distance > 0 {
if !isIdentifierPart(value) {
return "", fmt.Errorf("Invalid identifier escape value: %c (%s)", value, string(value))
}
}
}
self.read()
}
literal := string(self.str[offset:self.chrOffset])
if parse {
return parseStringLiteral(literal)
}
return literal, nil
}
// 7.2
func isLineWhiteSpace(chr rune) bool {
switch chr {
case '\u0009', '\u000b', '\u000c', '\u0020', '\u00a0', '\ufeff':
return true
case '\u000a', '\u000d', '\u2028', '\u2029':
return false
case '\u0085':
return false
}
return unicode.IsSpace(chr)
}
// 7.3
func isLineTerminator(chr rune) bool {
switch chr {
case '\u000a', '\u000d', '\u2028', '\u2029':
return true
}
return false
}
func (self *_parser) scan() (tkn token.Token, literal string, idx file.Idx) {
self.implicitSemicolon = false
for {
self.skipWhiteSpace()
idx = self.idxOf(self.chrOffset)
insertSemicolon := false
switch chr := self.chr; {
case isIdentifierStart(chr):
var err error
literal, err = self.scanIdentifier()
if err != nil {
tkn = token.ILLEGAL
break
}
if len(literal) > 1 {
// Keywords are longer than 1 character, avoid lookup otherwise
var strict bool
tkn, strict = token.IsKeyword(literal)
switch tkn {
case 0: // Not a keyword
if literal == "true" || literal == "false" {
self.insertSemicolon = true
tkn = token.BOOLEAN
return
} else if literal == "null" {
self.insertSemicolon = true
tkn = token.NULL
return
}
case token.KEYWORD:
tkn = token.KEYWORD
if strict {
// TODO If strict and in strict mode, then this is not a break
break
}
return
case
token.THIS,
token.BREAK,
token.THROW, // A newline after a throw is not allowed, but we need to detect it
token.RETURN,
token.CONTINUE,
token.DEBUGGER:
self.insertSemicolon = true
return
default:
return
}
}
self.insertSemicolon = true
tkn = token.IDENTIFIER
return
case '0' <= chr && chr <= '9':
self.insertSemicolon = true
tkn, literal = self.scanNumericLiteral(false)
return
default:
self.read()
switch chr {
case -1:
if self.insertSemicolon {
self.insertSemicolon = false
self.implicitSemicolon = true
}
tkn = token.EOF
case '\r', '\n', '\u2028', '\u2029':
self.insertSemicolon = false
self.implicitSemicolon = true
continue
case ':':
tkn = token.COLON
case '.':
if digitValue(self.chr) < 10 {
insertSemicolon = true
tkn, literal = self.scanNumericLiteral(true)
} else {
tkn = token.PERIOD
}
case ',':
tkn = token.COMMA
case ';':
tkn = token.SEMICOLON
case '(':
tkn = token.LEFT_PARENTHESIS
case ')':
tkn = token.RIGHT_PARENTHESIS
insertSemicolon = true
case '[':
tkn = token.LEFT_BRACKET
case ']':
tkn = token.RIGHT_BRACKET
insertSemicolon = true
case '{':
tkn = token.LEFT_BRACE
case '}':
tkn = token.RIGHT_BRACE
insertSemicolon = true
case '+':
tkn = self.switch3(token.PLUS, token.ADD_ASSIGN, '+', token.INCREMENT)
if tkn == token.INCREMENT {
insertSemicolon = true
}
case '-':
tkn = self.switch3(token.MINUS, token.SUBTRACT_ASSIGN, '-', token.DECREMENT)
if tkn == token.DECREMENT {
insertSemicolon = true
}
case '*':
tkn = self.switch2(token.MULTIPLY, token.MULTIPLY_ASSIGN)
case '/':
if self.chr == '/' {
self.skipSingleLineComment()
continue
} else if self.chr == '*' {
self.skipMultiLineComment()
continue
} else {
// Could be division, could be RegExp literal
tkn = self.switch2(token.SLASH, token.QUOTIENT_ASSIGN)
insertSemicolon = true
}
case '%':
tkn = self.switch2(token.REMAINDER, token.REMAINDER_ASSIGN)
case '^':
tkn = self.switch2(token.EXCLUSIVE_OR, token.EXCLUSIVE_OR_ASSIGN)
case '<':
tkn = self.switch4(token.LESS, token.LESS_OR_EQUAL, '<', token.SHIFT_LEFT, token.SHIFT_LEFT_ASSIGN)
case '>':
tkn = self.switch6(token.GREATER, token.GREATER_OR_EQUAL, '>', token.SHIFT_RIGHT, token.SHIFT_RIGHT_ASSIGN, '>', token.UNSIGNED_SHIFT_RIGHT, token.UNSIGNED_SHIFT_RIGHT_ASSIGN)
case '=':
tkn = self.switch2(token.ASSIGN, token.EQUAL)
if tkn == token.EQUAL && self.chr == '=' {
self.read()
tkn = token.STRICT_EQUAL
}
case '!':
tkn = self.switch2(token.NOT, token.NOT_EQUAL)
if tkn == token.NOT_EQUAL && self.chr == '=' {
self.read()
tkn = token.STRICT_NOT_EQUAL
}
case '&':
if self.chr == '^' {
self.read()
tkn = self.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
} else {
tkn = self.switch3(token.AND, token.AND_ASSIGN, '&', token.LOGICAL_AND)
}
case '|':
tkn = self.switch3(token.OR, token.OR_ASSIGN, '|', token.LOGICAL_OR)
case '~':
tkn = token.BITWISE_NOT
case '?':
tkn = token.QUESTION_MARK
case '"', '\'':
insertSemicolon = true
tkn = token.STRING
var err error
literal, err = self.scanString(self.chrOffset - 1)
if err != nil {
tkn = token.ILLEGAL
}
default:
self.errorUnexpected(idx, chr)
tkn = token.ILLEGAL
}
}
self.insertSemicolon = insertSemicolon
return
}
}
func (self *_parser) switch2(tkn0, tkn1 token.Token) token.Token {
if self.chr == '=' {
self.read()
return tkn1
}
return tkn0
}
func (self *_parser) switch3(tkn0, tkn1 token.Token, chr2 rune, tkn2 token.Token) token.Token {
if self.chr == '=' {
self.read()
return tkn1
}
if self.chr == chr2 {
self.read()
return tkn2
}
return tkn0
}
func (self *_parser) switch4(tkn0, tkn1 token.Token, chr2 rune, tkn2, tkn3 token.Token) token.Token {
if self.chr == '=' {
self.read()
return tkn1
}
if self.chr == chr2 {
self.read()
if self.chr == '=' {
self.read()
return tkn3
}
return tkn2
}
return tkn0
}
func (self *_parser) switch6(tkn0, tkn1 token.Token, chr2 rune, tkn2, tkn3 token.Token, chr3 rune, tkn4, tkn5 token.Token) token.Token {
if self.chr == '=' {
self.read()
return tkn1
}
if self.chr == chr2 {
self.read()
if self.chr == '=' {
self.read()
return tkn3
}
if self.chr == chr3 {
self.read()
if self.chr == '=' {
self.read()
return tkn5
}
return tkn4
}
return tkn2
}
return tkn0
}
func (self *_parser) chrAt(index int) _chr {
value, width := utf8.DecodeRuneInString(self.str[index:])
return _chr{
value: value,
width: width,
}
}
func (self *_parser) _peek() rune {
if self.offset+1 < self.length {
return rune(self.str[self.offset+1])
}
return -1
}
func (self *_parser) read() {
if self.offset < self.length {
self.chrOffset = self.offset
chr, width := rune(self.str[self.offset]), 1
if chr >= utf8.RuneSelf { // !ASCII
chr, width = utf8.DecodeRuneInString(self.str[self.offset:])
if chr == utf8.RuneError && width == 1 {
self.error(self.chrOffset, "Invalid UTF-8 character")
}
}
self.offset += width
self.chr = chr
} else {
self.chrOffset = self.length
self.chr = -1 // EOF
}
}
// This is here since the functions are so similar
func (self *_RegExp_parser) read() {
if self.offset < self.length {
self.chrOffset = self.offset
chr, width := rune(self.str[self.offset]), 1
if chr >= utf8.RuneSelf { // !ASCII
chr, width = utf8.DecodeRuneInString(self.str[self.offset:])
if chr == utf8.RuneError && width == 1 {
self.error(self.chrOffset, "Invalid UTF-8 character")
}
}
self.offset += width
self.chr = chr
} else {
self.chrOffset = self.length
self.chr = -1 // EOF
}
}
func (self *_parser) skipSingleLineComment() {
for self.chr != -1 {
self.read()
if isLineTerminator(self.chr) {
return
}
}
}
func (self *_parser) skipMultiLineComment() {
self.read()
for self.chr >= 0 {
chr := self.chr
self.read()
if chr == '*' && self.chr == '/' {
self.read()
return
}
}
self.errorUnexpected(0, self.chr)
}
func (self *_parser) skipWhiteSpace() {
for {
switch self.chr {
case ' ', '\t', '\f', '\v', '\u00a0', '\ufeff':
self.read()
continue
case '\r':
if self._peek() == '\n' {
self.read()
}
fallthrough
case '\u2028', '\u2029', '\n':
if self.insertSemicolon {
return
}
self.read()
continue
}
if self.chr >= utf8.RuneSelf {
if unicode.IsSpace(self.chr) {
self.read()
continue
}
}
break
}
}
func (self *_parser) skipLineWhiteSpace() {
for isLineWhiteSpace(self.chr) {
self.read()
}
}
func (self *_parser) scanMantissa(base int) {
for digitValue(self.chr) < base {
self.read()
}
}
func (self *_parser) scanEscape(quote rune) {
var length, base uint32
switch self.chr {
//case '0', '1', '2', '3', '4', '5', '6', '7':
// Octal:
// length, base, limit = 3, 8, 255
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"', '\'', '0':
self.read()
return
case '\r', '\n', '\u2028', '\u2029':
self.scanNewline()
return
case 'x':
self.read()
length, base = 2, 16
case 'u':
self.read()
length, base = 4, 16
default:
self.read() // Always make progress
return
}
var value uint32
for ; length > 0 && self.chr != quote && self.chr >= 0; length-- {
digit := uint32(digitValue(self.chr))
if digit >= base {
break
}
value = value*base + digit
self.read()
}
}
func (self *_parser) scanString(offset int) (string, error) {
// " ' /
quote := rune(self.str[offset])
for self.chr != quote {
chr := self.chr
if chr == '\n' || chr == '\r' || chr == '\u2028' || chr == '\u2029' || chr < 0 {
goto newline
}
self.read()
if chr == '\\' {
if quote == '/' {
if self.chr == '\n' || self.chr == '\r' || self.chr == '\u2028' || self.chr == '\u2029' || self.chr < 0 {
goto newline
}
self.read()
} else {
self.scanEscape(quote)
}
} else if chr == '[' && quote == '/' {
// Allow a slash (/) in a bracket character class ([...])
// TODO Fix this, this is hacky...
quote = -1
} else if chr == ']' && quote == -1 {
quote = '/'
}
}
// " ' /
self.read()
return string(self.str[offset:self.chrOffset]), nil
newline:
self.scanNewline()
err := "String not terminated"
if quote == '/' {
err = "Invalid regular expression: missing /"
self.error(self.idxOf(offset), err)
}
return "", errors.New(err)
}
func (self *_parser) scanNewline() {
if self.chr == '\r' {
self.read()
if self.chr != '\n' {
return
}
}
self.read()
}
func hex2decimal(chr byte) (value rune, ok bool) {
{
chr := rune(chr)
switch {
case '0' <= chr && chr <= '9':
return chr - '0', true
case 'a' <= chr && chr <= 'f':
return chr - 'a' + 10, true
case 'A' <= chr && chr <= 'F':
return chr - 'A' + 10, true
}
return
}
}
func parseNumberLiteral(literal string) (value interface{}, err error) {
// TODO Is Uint okay? What about -MAX_UINT
value, err = strconv.ParseInt(literal, 0, 64)
if err == nil {
return
}
parseIntErr := err // Save this first error, just in case
value, err = strconv.ParseFloat(literal, 64)
if err == nil {
return
} else if err.(*strconv.NumError).Err == strconv.ErrRange {
// Infinity, etc.
return value, nil
}
err = parseIntErr
if err.(*strconv.NumError).Err == strconv.ErrRange {
if len(literal) > 2 && literal[0] == '0' && (literal[1] == 'X' || literal[1] == 'x') {
// Could just be a very large number (e.g. 0x8000000000000000)
var value float64
literal = literal[2:]
for _, chr := range literal {
digit := digitValue(chr)
if digit >= 16 {
goto error
}
value = value*16 + float64(digit)
}
return value, nil
}
}
error:
return nil, errors.New("Illegal numeric literal")
}
func parseStringLiteral(literal string) (string, error) {
// Best case scenario...
if literal == "" {
return "", nil
}
// Slightly less-best case scenario...
if !strings.ContainsRune(literal, '\\') {
return literal, nil
}
str := literal
buffer := bytes.NewBuffer(make([]byte, 0, 3*len(literal)/2))
for len(str) > 0 {
switch chr := str[0]; {
// We do not explicitly handle the case of the quote
// value, which can be: " ' /
// This assumes we're already passed a partially well-formed literal
case chr >= utf8.RuneSelf:
chr, size := utf8.DecodeRuneInString(str)
buffer.WriteRune(chr)
str = str[size:]
continue
case chr != '\\':
buffer.WriteByte(chr)
str = str[1:]
continue
}
if len(str) <= 1 {
panic("len(str) <= 1")
}
chr := str[1]
var value rune
if chr >= utf8.RuneSelf {
str = str[1:]
var size int
value, size = utf8.DecodeRuneInString(str)
str = str[size:] // \ + <character>
} else {
str = str[2:] // \<character>
switch chr {
case 'b':
value = '\b'
case 'f':
value = '\f'
case 'n':
value = '\n'
case 'r':
value = '\r'
case 't':
value = '\t'
case 'v':
value = '\v'
case 'x', 'u':
size := 0
switch chr {
case 'x':
size = 2
case 'u':
size = 4
}
if len(str) < size {
return "", fmt.Errorf("invalid escape: \\%s: len(%q) != %d", string(chr), str, size)
}
for j := 0; j < size; j++ {
decimal, ok := hex2decimal(str[j])
if !ok {
return "", fmt.Errorf("invalid escape: \\%s: %q", string(chr), str[:size])
}
value = value<<4 | decimal
}
str = str[size:]
if chr == 'x' {
break
}
if value > utf8.MaxRune {
panic("value > utf8.MaxRune")
}
case '0':
if len(str) == 0 || '0' > str[0] || str[0] > '7' {
value = 0
break
}
fallthrough
case '1', '2', '3', '4', '5', '6', '7':
// TODO strict
value = rune(chr) - '0'
j := 0
for ; j < 2; j++ {
if len(str) < j+1 {
break
}
chr := str[j]
if '0' > chr || chr > '7' {
break
}
decimal := rune(str[j]) - '0'
value = (value << 3) | decimal
}
str = str[j:]
case '\\':
value = '\\'
case '\'', '"':
value = rune(chr)
case '\r':
if len(str) > 0 {
if str[0] == '\n' {
str = str[1:]
}
}
fallthrough
case '\n':
continue
default:
value = rune(chr)
}
}
buffer.WriteRune(value)
}
return buffer.String(), nil
}
func (self *_parser) scanNumericLiteral(decimalPoint bool) (token.Token, string) {
offset := self.chrOffset
tkn := token.NUMBER
if decimalPoint {
offset--
self.scanMantissa(10)
goto exponent
}
if self.chr == '0' {
offset := self.chrOffset
self.read()
if self.chr == 'x' || self.chr == 'X' {
// Hexadecimal
self.read()
if isDigit(self.chr, 16) {
self.read()
} else {
return token.ILLEGAL, self.str[offset:self.chrOffset]
}
self.scanMantissa(16)
if self.chrOffset-offset <= 2 {
// Only "0x" or "0X"
self.error(0, "Illegal hexadecimal number")
}
goto hexadecimal
} else if self.chr == '.' {
// Float
goto float
} else {
// Octal, Float
if self.chr == 'e' || self.chr == 'E' {
goto exponent
}
self.scanMantissa(8)
if self.chr == '8' || self.chr == '9' {
return token.ILLEGAL, self.str[offset:self.chrOffset]
}
goto octal
}
}
self.scanMantissa(10)
float:
if self.chr == '.' {
self.read()
self.scanMantissa(10)
}
exponent:
if self.chr == 'e' || self.chr == 'E' {
self.read()
if self.chr == '-' || self.chr == '+' {
self.read()
}
if isDecimalDigit(self.chr) {
self.read()
self.scanMantissa(10)
} else {
return token.ILLEGAL, self.str[offset:self.chrOffset]
}
}
hexadecimal:
octal:
if isIdentifierStart(self.chr) || isDecimalDigit(self.chr) {
return token.ILLEGAL, self.str[offset:self.chrOffset]
}
return tkn, self.str[offset:self.chrOffset]
}

View file

@ -1,380 +0,0 @@
package parser
import (
"../terst"
"testing"
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
var tt = terst.Terst
var is = terst.Is
func TestLexer(t *testing.T) {
tt(t, func() {
setup := func(src string) *_parser {
parser := newParser("", src)
return parser
}
test := func(src string, test ...interface{}) {
parser := setup(src)
for len(test) > 0 {
tkn, literal, idx := parser.scan()
if len(test) > 0 {
is(tkn, test[0].(token.Token))
test = test[1:]
}
if len(test) > 0 {
is(literal, test[0].(string))
test = test[1:]
}
if len(test) > 0 {
// FIXME terst, Fix this so that cast to file.Idx is not necessary?
is(idx, file.Idx(test[0].(int)))
test = test[1:]
}
}
}
test("",
token.EOF, "", 1,
)
test("1",
token.NUMBER, "1", 1,
token.EOF, "", 2,
)
test(".0",
token.NUMBER, ".0", 1,
token.EOF, "", 3,
)
test("abc",
token.IDENTIFIER, "abc", 1,
token.EOF, "", 4,
)
test("abc(1)",
token.IDENTIFIER, "abc", 1,
token.LEFT_PARENTHESIS, "", 4,
token.NUMBER, "1", 5,
token.RIGHT_PARENTHESIS, "", 6,
token.EOF, "", 7,
)
test(".",
token.PERIOD, "", 1,
token.EOF, "", 2,
)
test("===.",
token.STRICT_EQUAL, "", 1,
token.PERIOD, "", 4,
token.EOF, "", 5,
)
test(">>>=.0",
token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1,
token.NUMBER, ".0", 5,
token.EOF, "", 7,
)
test(">>>=0.0.",
token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1,
token.NUMBER, "0.0", 5,
token.PERIOD, "", 8,
token.EOF, "", 9,
)
test("\"abc\"",
token.STRING, "\"abc\"", 1,
token.EOF, "", 6,
)
test("abc = //",
token.IDENTIFIER, "abc", 1,
token.ASSIGN, "", 5,
token.EOF, "", 9,
)
test("abc = 1 / 2",
token.IDENTIFIER, "abc", 1,
token.ASSIGN, "", 5,
token.NUMBER, "1", 7,
token.SLASH, "", 9,
token.NUMBER, "2", 11,
token.EOF, "", 12,
)
test("xyzzy = 'Nothing happens.'",
token.IDENTIFIER, "xyzzy", 1,
token.ASSIGN, "", 7,
token.STRING, "'Nothing happens.'", 9,
token.EOF, "", 27,
)
test("abc = !false",
token.IDENTIFIER, "abc", 1,
token.ASSIGN, "", 5,
token.NOT, "", 7,
token.BOOLEAN, "false", 8,
token.EOF, "", 13,
)
test("abc = !!true",
token.IDENTIFIER, "abc", 1,
token.ASSIGN, "", 5,
token.NOT, "", 7,
token.NOT, "", 8,
token.BOOLEAN, "true", 9,
token.EOF, "", 13,
)
test("abc *= 1",
token.IDENTIFIER, "abc", 1,
token.MULTIPLY_ASSIGN, "", 5,
token.NUMBER, "1", 8,
token.EOF, "", 9,
)
test("if 1 else",
token.IF, "if", 1,
token.NUMBER, "1", 4,
token.ELSE, "else", 6,
token.EOF, "", 10,
)
test("null",
token.NULL, "null", 1,
token.EOF, "", 5,
)
test(`"\u007a\x79\u000a\x78"`,
token.STRING, "\"\\u007a\\x79\\u000a\\x78\"", 1,
token.EOF, "", 23,
)
test(`"[First line \
Second line \
Third line\
. ]"
`,
token.STRING, "\"[First line \\\nSecond line \\\n Third line\\\n. ]\"", 1,
token.EOF, "", 53,
)
test("/",
token.SLASH, "", 1,
token.EOF, "", 2,
)
test("var abc = \"abc\uFFFFabc\"",
token.VAR, "var", 1,
token.IDENTIFIER, "abc", 5,
token.ASSIGN, "", 9,
token.STRING, "\"abc\uFFFFabc\"", 11,
token.EOF, "", 22,
)
test(`'\t' === '\r'`,
token.STRING, "'\\t'", 1,
token.STRICT_EQUAL, "", 6,
token.STRING, "'\\r'", 10,
token.EOF, "", 14,
)
test(`var \u0024 = 1`,
token.VAR, "var", 1,
token.IDENTIFIER, "$", 5,
token.ASSIGN, "", 12,
token.NUMBER, "1", 14,
token.EOF, "", 15,
)
test("10e10000",
token.NUMBER, "10e10000", 1,
token.EOF, "", 9,
)
test(`var if var class`,
token.VAR, "var", 1,
token.IF, "if", 5,
token.VAR, "var", 8,
token.KEYWORD, "class", 12,
token.EOF, "", 17,
)
test(`-0`,
token.MINUS, "", 1,
token.NUMBER, "0", 2,
token.EOF, "", 3,
)
test(`.01`,
token.NUMBER, ".01", 1,
token.EOF, "", 4,
)
test(`.01e+2`,
token.NUMBER, ".01e+2", 1,
token.EOF, "", 7,
)
test(";",
token.SEMICOLON, "", 1,
token.EOF, "", 2,
)
test(";;",
token.SEMICOLON, "", 1,
token.SEMICOLON, "", 2,
token.EOF, "", 3,
)
test("//",
token.EOF, "", 3,
)
test(";;//",
token.SEMICOLON, "", 1,
token.SEMICOLON, "", 2,
token.EOF, "", 5,
)
test("1",
token.NUMBER, "1", 1,
)
test("12 123",
token.NUMBER, "12", 1,
token.NUMBER, "123", 4,
)
test("1.2 12.3",
token.NUMBER, "1.2", 1,
token.NUMBER, "12.3", 5,
)
test("/ /=",
token.SLASH, "", 1,
token.QUOTIENT_ASSIGN, "", 3,
)
test(`"abc"`,
token.STRING, `"abc"`, 1,
)
test(`'abc'`,
token.STRING, `'abc'`, 1,
)
test("++",
token.INCREMENT, "", 1,
)
test(">",
token.GREATER, "", 1,
)
test(">=",
token.GREATER_OR_EQUAL, "", 1,
)
test(">>",
token.SHIFT_RIGHT, "", 1,
)
test(">>=",
token.SHIFT_RIGHT_ASSIGN, "", 1,
)
test(">>>",
token.UNSIGNED_SHIFT_RIGHT, "", 1,
)
test(">>>=",
token.UNSIGNED_SHIFT_RIGHT_ASSIGN, "", 1,
)
test("1 \"abc\"",
token.NUMBER, "1", 1,
token.STRING, "\"abc\"", 3,
)
test(",",
token.COMMA, "", 1,
)
test("1, \"abc\"",
token.NUMBER, "1", 1,
token.COMMA, "", 2,
token.STRING, "\"abc\"", 4,
)
test("new abc(1, 3.14159);",
token.NEW, "new", 1,
token.IDENTIFIER, "abc", 5,
token.LEFT_PARENTHESIS, "", 8,
token.NUMBER, "1", 9,
token.COMMA, "", 10,
token.NUMBER, "3.14159", 12,
token.RIGHT_PARENTHESIS, "", 19,
token.SEMICOLON, "", 20,
)
test("1 == \"1\"",
token.NUMBER, "1", 1,
token.EQUAL, "", 3,
token.STRING, "\"1\"", 6,
)
test("1\n[]\n",
token.NUMBER, "1", 1,
token.LEFT_BRACKET, "", 3,
token.RIGHT_BRACKET, "", 4,
)
test("1\ufeff[]\ufeff",
token.NUMBER, "1", 1,
token.LEFT_BRACKET, "", 5,
token.RIGHT_BRACKET, "", 6,
)
// ILLEGAL
test(`3ea`,
token.ILLEGAL, "3e", 1,
token.IDENTIFIER, "a", 3,
token.EOF, "", 4,
)
test(`3in`,
token.ILLEGAL, "3", 1,
token.IN, "in", 2,
token.EOF, "", 4,
)
test("\"Hello\nWorld\"",
token.ILLEGAL, "", 1,
token.IDENTIFIER, "World", 8,
token.ILLEGAL, "", 13,
token.EOF, "", 14,
)
test("\u203f = 10",
token.ILLEGAL, "", 1,
token.ASSIGN, "", 5,
token.NUMBER, "10", 7,
token.EOF, "", 9,
)
test(`"\x0G"`,
token.STRING, "\"\\x0G\"", 1,
token.EOF, "", 7,
)
})
}

View file

@ -1,930 +0,0 @@
package parser
import (
"bytes"
"encoding/json"
"fmt"
"os"
"reflect"
"strings"
"testing"
"github.com/robertkrimen/otto/ast"
)
func marshal(name string, children ...interface{}) interface{} {
if len(children) == 1 {
if name == "" {
return testMarshalNode(children[0])
}
return map[string]interface{}{
name: children[0],
}
}
map_ := map[string]interface{}{}
length := len(children) / 2
for i := 0; i < length; i++ {
name := children[i*2].(string)
value := children[i*2+1]
map_[name] = value
}
if name == "" {
return map_
}
return map[string]interface{}{
name: map_,
}
}
func testMarshalNode(node interface{}) interface{} {
switch node := node.(type) {
// Expression
case *ast.ArrayLiteral:
return marshal("Array", testMarshalNode(node.Value))
case *ast.AssignExpression:
return marshal("Assign",
"Left", testMarshalNode(node.Left),
"Right", testMarshalNode(node.Right),
)
case *ast.BinaryExpression:
return marshal("BinaryExpression",
"Operator", node.Operator.String(),
"Left", testMarshalNode(node.Left),
"Right", testMarshalNode(node.Right),
)
case *ast.BooleanLiteral:
return marshal("Literal", node.Value)
case *ast.CallExpression:
return marshal("Call",
"Callee", testMarshalNode(node.Callee),
"ArgumentList", testMarshalNode(node.ArgumentList),
)
case *ast.ConditionalExpression:
return marshal("Conditional",
"Test", testMarshalNode(node.Test),
"Consequent", testMarshalNode(node.Consequent),
"Alternate", testMarshalNode(node.Alternate),
)
case *ast.DotExpression:
return marshal("Dot",
"Left", testMarshalNode(node.Left),
"Member", node.Identifier.Name,
)
case *ast.NewExpression:
return marshal("New",
"Callee", testMarshalNode(node.Callee),
"ArgumentList", testMarshalNode(node.ArgumentList),
)
case *ast.NullLiteral:
return marshal("Literal", nil)
case *ast.NumberLiteral:
return marshal("Literal", node.Value)
case *ast.ObjectLiteral:
return marshal("Object", testMarshalNode(node.Value))
case *ast.RegExpLiteral:
return marshal("Literal", node.Literal)
case *ast.StringLiteral:
return marshal("Literal", node.Literal)
case *ast.VariableExpression:
return []interface{}{node.Name, testMarshalNode(node.Initializer)}
// Statement
case *ast.Program:
return testMarshalNode(node.Body)
case *ast.BlockStatement:
return marshal("BlockStatement", testMarshalNode(node.List))
case *ast.EmptyStatement:
return "EmptyStatement"
case *ast.ExpressionStatement:
return testMarshalNode(node.Expression)
case *ast.ForInStatement:
return marshal("ForIn",
"Into", marshal("", node.Into),
"Source", marshal("", node.Source),
"Body", marshal("", node.Body),
)
case *ast.FunctionLiteral:
return marshal("Function", testMarshalNode(node.Body))
case *ast.Identifier:
return marshal("Identifier", node.Name)
case *ast.IfStatement:
if_ := marshal("",
"Test", testMarshalNode(node.Test),
"Consequent", testMarshalNode(node.Consequent),
).(map[string]interface{})
if node.Alternate != nil {
if_["Alternate"] = testMarshalNode(node.Alternate)
}
return marshal("If", if_)
case *ast.LabelledStatement:
return marshal("Label",
"Name", node.Label.Name,
"Statement", testMarshalNode(node.Statement),
)
case ast.Property:
return marshal("",
"Key", node.Key,
"Value", testMarshalNode(node.Value),
)
case *ast.ReturnStatement:
return marshal("Return", testMarshalNode(node.Argument))
case *ast.SequenceExpression:
return marshal("Sequence", testMarshalNode(node.Sequence))
case *ast.ThrowStatement:
return marshal("Throw", testMarshalNode(node.Argument))
case *ast.VariableStatement:
return marshal("Var", testMarshalNode(node.List))
}
{
value := reflect.ValueOf(node)
if value.Kind() == reflect.Slice {
tmp0 := []interface{}{}
for index := 0; index < value.Len(); index++ {
tmp0 = append(tmp0, testMarshalNode(value.Index(index).Interface()))
}
return tmp0
}
}
if node != nil {
fmt.Fprintf(os.Stderr, "testMarshalNode(%T)\n", node)
}
return nil
}
func testMarshal(node interface{}) string {
value, err := json.Marshal(testMarshalNode(node))
if err != nil {
panic(err)
}
return string(value)
}
func TestParserAST(t *testing.T) {
tt(t, func() {
test := func(inputOutput string) {
match := matchBeforeAfterSeparator.FindStringIndex(inputOutput)
input := strings.TrimSpace(inputOutput[0:match[0]])
wantOutput := strings.TrimSpace(inputOutput[match[1]:])
_, program, err := testParse(input)
is(err, nil)
haveOutput := testMarshal(program)
tmp0, tmp1 := bytes.Buffer{}, bytes.Buffer{}
json.Indent(&tmp0, []byte(haveOutput), "\t\t", " ")
json.Indent(&tmp1, []byte(wantOutput), "\t\t", " ")
is("\n\t\t"+tmp0.String(), "\n\t\t"+tmp1.String())
}
test(`
---
[]
`)
test(`
;
---
[
"EmptyStatement"
]
`)
test(`
;;;
---
[
"EmptyStatement",
"EmptyStatement",
"EmptyStatement"
]
`)
test(`
1; true; abc; "abc"; null;
---
[
{
"Literal": 1
},
{
"Literal": true
},
{
"Identifier": "abc"
},
{
"Literal": "\"abc\""
},
{
"Literal": null
}
]
`)
test(`
{ 1; null; 3.14159; ; }
---
[
{
"BlockStatement": [
{
"Literal": 1
},
{
"Literal": null
},
{
"Literal": 3.14159
},
"EmptyStatement"
]
}
]
`)
test(`
new abc();
---
[
{
"New": {
"ArgumentList": [],
"Callee": {
"Identifier": "abc"
}
}
}
]
`)
test(`
new abc(1, 3.14159)
---
[
{
"New": {
"ArgumentList": [
{
"Literal": 1
},
{
"Literal": 3.14159
}
],
"Callee": {
"Identifier": "abc"
}
}
}
]
`)
test(`
true ? false : true
---
[
{
"Conditional": {
"Alternate": {
"Literal": true
},
"Consequent": {
"Literal": false
},
"Test": {
"Literal": true
}
}
}
]
`)
test(`
true || false
---
[
{
"BinaryExpression": {
"Left": {
"Literal": true
},
"Operator": "||",
"Right": {
"Literal": false
}
}
}
]
`)
test(`
0 + { abc: true }
---
[
{
"BinaryExpression": {
"Left": {
"Literal": 0
},
"Operator": "+",
"Right": {
"Object": [
{
"Key": "abc",
"Value": {
"Literal": true
}
}
]
}
}
}
]
`)
test(`
1 == "1"
---
[
{
"BinaryExpression": {
"Left": {
"Literal": 1
},
"Operator": "==",
"Right": {
"Literal": "\"1\""
}
}
}
]
`)
test(`
abc(1)
---
[
{
"Call": {
"ArgumentList": [
{
"Literal": 1
}
],
"Callee": {
"Identifier": "abc"
}
}
}
]
`)
test(`
Math.pow(3, 2)
---
[
{
"Call": {
"ArgumentList": [
{
"Literal": 3
},
{
"Literal": 2
}
],
"Callee": {
"Dot": {
"Left": {
"Identifier": "Math"
},
"Member": "pow"
}
}
}
}
]
`)
test(`
1, 2, 3
---
[
{
"Sequence": [
{
"Literal": 1
},
{
"Literal": 2
},
{
"Literal": 3
}
]
}
]
`)
test(`
/ abc / gim;
---
[
{
"Literal": "/ abc / gim"
}
]
`)
test(`
if (0)
1;
---
[
{
"If": {
"Consequent": {
"Literal": 1
},
"Test": {
"Literal": 0
}
}
}
]
`)
test(`
0+function(){
return;
}
---
[
{
"BinaryExpression": {
"Left": {
"Literal": 0
},
"Operator": "+",
"Right": {
"Function": {
"BlockStatement": [
{
"Return": null
}
]
}
}
}
}
]
`)
test(`
xyzzy // Ignore it
// Ignore this
// And this
/* And all..
... of this!
*/
"Nothing happens."
// And finally this
---
[
{
"Identifier": "xyzzy"
},
{
"Literal": "\"Nothing happens.\""
}
]
`)
test(`
((x & (x = 1)) !== 0)
---
[
{
"BinaryExpression": {
"Left": {
"BinaryExpression": {
"Left": {
"Identifier": "x"
},
"Operator": "\u0026",
"Right": {
"Assign": {
"Left": {
"Identifier": "x"
},
"Right": {
"Literal": 1
}
}
}
}
},
"Operator": "!==",
"Right": {
"Literal": 0
}
}
}
]
`)
test(`
{ abc: 'def' }
---
[
{
"BlockStatement": [
{
"Label": {
"Name": "abc",
"Statement": {
"Literal": "'def'"
}
}
}
]
}
]
`)
test(`
// This is not an object, this is a string literal with a label!
({ abc: 'def' })
---
[
{
"Object": [
{
"Key": "abc",
"Value": {
"Literal": "'def'"
}
}
]
}
]
`)
test(`
[,]
---
[
{
"Array": [
null
]
}
]
`)
test(`
[,,]
---
[
{
"Array": [
null,
null
]
}
]
`)
test(`
({ get abc() {} })
---
[
{
"Object": [
{
"Key": "abc",
"Value": {
"Function": {
"BlockStatement": []
}
}
}
]
}
]
`)
test(`
/abc/.source
---
[
{
"Dot": {
"Left": {
"Literal": "/abc/"
},
"Member": "source"
}
}
]
`)
test(`
xyzzy
throw new TypeError("Nothing happens.")
---
[
{
"Identifier": "xyzzy"
},
{
"Throw": {
"New": {
"ArgumentList": [
{
"Literal": "\"Nothing happens.\""
}
],
"Callee": {
"Identifier": "TypeError"
}
}
}
}
]
`)
// When run, this will call a type error to be thrown
// This is essentially the same as:
//
// var abc = 1(function(){})()
//
test(`
var abc = 1
(function(){
})()
---
[
{
"Var": [
[
"abc",
{
"Call": {
"ArgumentList": [],
"Callee": {
"Call": {
"ArgumentList": [
{
"Function": {
"BlockStatement": []
}
}
],
"Callee": {
"Literal": 1
}
}
}
}
}
]
]
}
]
`)
test(`
"use strict"
---
[
{
"Literal": "\"use strict\""
}
]
`)
test(`
"use strict"
abc = 1 + 2 + 11
---
[
{
"Literal": "\"use strict\""
},
{
"Assign": {
"Left": {
"Identifier": "abc"
},
"Right": {
"BinaryExpression": {
"Left": {
"BinaryExpression": {
"Left": {
"Literal": 1
},
"Operator": "+",
"Right": {
"Literal": 2
}
}
},
"Operator": "+",
"Right": {
"Literal": 11
}
}
}
}
}
]
`)
test(`
abc = function() { 'use strict' }
---
[
{
"Assign": {
"Left": {
"Identifier": "abc"
},
"Right": {
"Function": {
"BlockStatement": [
{
"Literal": "'use strict'"
}
]
}
}
}
}
]
`)
test(`
for (var abc in def) {
}
---
[
{
"ForIn": {
"Body": {
"BlockStatement": []
},
"Into": [
"abc",
null
],
"Source": {
"Identifier": "def"
}
}
}
]
`)
test(`
abc = {
'"': "'",
"'": '"',
}
---
[
{
"Assign": {
"Left": {
"Identifier": "abc"
},
"Right": {
"Object": [
{
"Key": "\"",
"Value": {
"Literal": "\"'\""
}
},
{
"Key": "'",
"Value": {
"Literal": "'\"'"
}
}
]
}
}
}
]
`)
return
test(`
if (!abc && abc.jkl(def) && abc[0] === +abc[0] && abc.length < ghi) {
}
---
[
{
"If": {
"Consequent": {
"BlockStatement": []
},
"Test": {
"BinaryExpression": {
"Left": {
"BinaryExpression": {
"Left": {
"BinaryExpression": {
"Left": null,
"Operator": "\u0026\u0026",
"Right": {
"Call": {
"ArgumentList": [
{
"Identifier": "def"
}
],
"Callee": {
"Dot": {
"Left": {
"Identifier": "abc"
},
"Member": "jkl"
}
}
}
}
}
},
"Operator": "\u0026\u0026",
"Right": {
"BinaryExpression": {
"Left": null,
"Operator": "===",
"Right": null
}
}
}
},
"Operator": "\u0026\u0026",
"Right": {
"BinaryExpression": {
"Left": {
"Dot": {
"Left": {
"Identifier": "abc"
},
"Member": "length"
}
},
"Operator": "\u003c",
"Right": {
"Identifier": "ghi"
}
}
}
}
}
}
}
]
`)
})
}

View file

@ -1,270 +0,0 @@
/*
Package parser implements a parser for JavaScript.
import (
"github.com/robertkrimen/otto/parser"
)
Parse and return an AST
filename := "" // A filename is optional
src := `
// Sample xyzzy example
(function(){
if (3.14159 > 0) {
console.log("Hello, World.");
return;
}
var xyzzy = NaN;
console.log("Nothing happens.");
return xyzzy;
})();
`
// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, filename, src, 0)
Warning
The parser and AST interfaces are still works-in-progress (particularly where
node types are concerned) and may change in the future.
*/
package parser
import (
"bytes"
"errors"
"io"
"io/ioutil"
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/file"
"github.com/robertkrimen/otto/token"
)
// A Mode value is a set of flags (or 0). They control optional parser functionality.
type Mode uint
const (
IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
)
type _parser struct {
filename string
str string
length int
base int
chr rune // The current character
chrOffset int // The offset of current character
offset int // The offset after current character (may be greater than 1)
idx file.Idx // The index of token
token token.Token // The token
literal string // The literal of the token, if any
scope *_scope
insertSemicolon bool // If we see a newline, then insert an implicit semicolon
implicitSemicolon bool // An implicit semicolon exists
errors ErrorList
recover struct {
// Scratch when trying to seek to the next statement, etc.
idx file.Idx
count int
}
mode Mode
}
func _newParser(filename, src string, base int) *_parser {
return &_parser{
chr: ' ', // This is set so we can start scanning by skipping whitespace
str: src,
length: len(src),
base: base,
}
}
func newParser(filename, src string) *_parser {
return _newParser(filename, src, 1)
}
func ReadSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch src := src.(type) {
case string:
return []byte(src), nil
case []byte:
return src, nil
case *bytes.Buffer:
if src != nil {
return src.Bytes(), nil
}
case io.Reader:
var bfr bytes.Buffer
if _, err := io.Copy(&bfr, src); err != nil {
return nil, err
}
return bfr.Bytes(), nil
}
return nil, errors.New("invalid source")
}
return ioutil.ReadFile(filename)
}
// ParseFile parses the source code of a single JavaScript/ECMAScript source file and returns
// the corresponding ast.Program node.
//
// If fileSet == nil, ParseFile parses source without a FileSet.
// If fileSet != nil, ParseFile first adds filename and src to fileSet.
//
// The filename argument is optional and is used for labelling errors, etc.
//
// src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.
//
// // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
// program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0)
//
func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error) {
str, err := ReadSource(filename, src)
if err != nil {
return nil, err
}
{
str := string(str)
base := 1
if fileSet != nil {
base = fileSet.AddFile(filename, str)
}
parser := _newParser(filename, str, base)
parser.mode = mode
return parser.parse()
}
}
// ParseFunction parses a given parameter list and body as a function and returns the
// corresponding ast.FunctionLiteral node.
//
// The parameter list, if any, should be a comma-separated list of identifiers.
//
func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error) {
src := "(function(" + parameterList + ") {\n" + body + "\n})"
parser := _newParser("", src, 1)
program, err := parser.parse()
if err != nil {
return nil, err
}
return program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral), nil
}
func (self *_parser) slice(idx0, idx1 file.Idx) string {
from := int(idx0) - self.base
to := int(idx1) - self.base
if from >= 0 && to <= len(self.str) {
return self.str[from:to]
}
return ""
}
func (self *_parser) parse() (*ast.Program, error) {
self.next()
program := self.parseProgram()
if false {
self.errors.Sort()
}
return program, self.errors.Err()
}
func (self *_parser) next() {
self.token, self.literal, self.idx = self.scan()
}
func (self *_parser) optionalSemicolon() {
if self.token == token.SEMICOLON {
self.next()
return
}
if self.implicitSemicolon {
self.implicitSemicolon = false
return
}
if self.token != token.EOF && self.token != token.RIGHT_BRACE {
self.expect(token.SEMICOLON)
}
}
func (self *_parser) semicolon() {
if self.token != token.RIGHT_PARENTHESIS && self.token != token.RIGHT_BRACE {
if self.implicitSemicolon {
self.implicitSemicolon = false
return
}
self.expect(token.SEMICOLON)
}
}
func (self *_parser) idxOf(offset int) file.Idx {
return file.Idx(self.base + offset)
}
func (self *_parser) expect(value token.Token) file.Idx {
idx := self.idx
if self.token != value {
self.errorUnexpectedToken(self.token)
}
self.next()
return idx
}
func lineCount(str string) (int, int) {
line, last := 0, -1
pair := false
for index, chr := range str {
switch chr {
case '\r':
line += 1
last = index
pair = true
continue
case '\n':
if !pair {
line += 1
}
last = index
case '\u2028', '\u2029':
line += 1
last = index + 2
}
pair = false
}
return line, last
}
func (self *_parser) position(idx file.Idx) file.Position {
position := file.Position{}
offset := int(idx) - self.base
str := self.str[:offset]
position.Filename = self.filename
line, last := lineCount(str)
position.Line = 1 + line
if last >= 0 {
position.Column = offset - last
} else {
position.Column = 1 + len(str)
}
return position
}

File diff suppressed because it is too large Load diff

View file

@ -1,358 +0,0 @@
package parser
import (
"bytes"
"fmt"
"strconv"
)
type _RegExp_parser struct {
str string
length int
chr rune // The current character
chrOffset int // The offset of current character
offset int // The offset after current character (may be greater than 1)
errors []error
invalid bool // The input is an invalid JavaScript RegExp
goRegexp *bytes.Buffer
}
// TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern.
//
// re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or
// backreference (\1, \2, ...) will cause an error.
//
// re2 (Go) has a different definition for \s: [\t\n\f\r ].
// The JavaScript definition, on the other hand, also includes \v, Unicode "Separator, Space", etc.
//
// If the pattern is invalid (not valid even in JavaScript), then this function
// returns the empty string and an error.
//
// If the pattern is valid, but incompatible (contains a lookahead or backreference),
// then this function returns the transformation (a non-empty string) AND an error.
func TransformRegExp(pattern string) (string, error) {
if pattern == "" {
return "", nil
}
// TODO If without \, if without (?=, (?!, then another shortcut
parser := _RegExp_parser{
str: pattern,
length: len(pattern),
goRegexp: bytes.NewBuffer(make([]byte, 0, 3*len(pattern)/2)),
}
parser.read() // Pull in the first character
parser.scan()
var err error
if len(parser.errors) > 0 {
err = parser.errors[0]
}
if parser.invalid {
return "", err
}
// Might not be re2 compatible, but is still a valid JavaScript RegExp
return parser.goRegexp.String(), err
}
func (self *_RegExp_parser) scan() {
for self.chr != -1 {
switch self.chr {
case '\\':
self.read()
self.scanEscape(false)
case '(':
self.pass()
self.scanGroup()
case '[':
self.pass()
self.scanBracket()
case ')':
self.error(-1, "Unmatched ')'")
self.invalid = true
self.pass()
default:
self.pass()
}
}
}
// (...)
func (self *_RegExp_parser) scanGroup() {
str := self.str[self.chrOffset:]
if len(str) > 1 { // A possibility of (?= or (?!
if str[0] == '?' {
if str[1] == '=' || str[1] == '!' {
self.error(-1, "re2: Invalid (%s) <lookahead>", self.str[self.chrOffset:self.chrOffset+2])
}
}
}
for self.chr != -1 && self.chr != ')' {
switch self.chr {
case '\\':
self.read()
self.scanEscape(false)
case '(':
self.pass()
self.scanGroup()
case '[':
self.pass()
self.scanBracket()
default:
self.pass()
continue
}
}
if self.chr != ')' {
self.error(-1, "Unterminated group")
self.invalid = true
return
}
self.pass()
}
// [...]
func (self *_RegExp_parser) scanBracket() {
for self.chr != -1 {
if self.chr == ']' {
break
} else if self.chr == '\\' {
self.read()
self.scanEscape(true)
continue
}
self.pass()
}
if self.chr != ']' {
self.error(-1, "Unterminated character class")
self.invalid = true
return
}
self.pass()
}
// \...
func (self *_RegExp_parser) scanEscape(inClass bool) {
offset := self.chrOffset
var length, base uint32
switch self.chr {
case '0', '1', '2', '3', '4', '5', '6', '7':
var value int64
size := 0
for {
digit := int64(digitValue(self.chr))
if digit >= 8 {
// Not a valid digit
break
}
value = value*8 + digit
self.read()
size += 1
}
if size == 1 { // The number of characters read
_, err := self.goRegexp.Write([]byte{'\\', byte(value) + '0'})
if err != nil {
self.errors = append(self.errors, err)
}
if value != 0 {
// An invalid backreference
self.error(-1, "re2: Invalid \\%d <backreference>", value)
}
return
}
tmp := []byte{'\\', 'x', '0', 0}
if value >= 16 {
tmp = tmp[0:2]
} else {
tmp = tmp[0:3]
}
tmp = strconv.AppendInt(tmp, value, 16)
_, err := self.goRegexp.Write(tmp)
if err != nil {
self.errors = append(self.errors, err)
}
return
case '8', '9':
size := 0
for {
digit := digitValue(self.chr)
if digit >= 10 {
// Not a valid digit
break
}
self.read()
size += 1
}
err := self.goRegexp.WriteByte('\\')
if err != nil {
self.errors = append(self.errors, err)
}
_, err = self.goRegexp.WriteString(self.str[offset:self.chrOffset])
if err != nil {
self.errors = append(self.errors, err)
}
self.error(-1, "re2: Invalid \\%s <backreference>", self.str[offset:self.chrOffset])
return
case 'x':
self.read()
length, base = 2, 16
case 'u':
self.read()
length, base = 4, 16
case 'b':
if inClass {
_, err := self.goRegexp.Write([]byte{'\\', 'x', '0', '8'})
if err != nil {
self.errors = append(self.errors, err)
}
self.read()
return
}
fallthrough
case 'B':
fallthrough
case 'd', 'D', 's', 'S', 'w', 'W':
// This is slightly broken, because ECMAScript
// includes \v in \s, \S, while re2 does not
fallthrough
case '\\':
fallthrough
case 'f', 'n', 'r', 't', 'v':
err := self.goRegexp.WriteByte('\\')
if err != nil {
self.errors = append(self.errors, err)
}
self.pass()
return
case 'c':
self.read()
var value int64
if 'a' <= self.chr && self.chr <= 'z' {
value = int64(self.chr) - 'a' + 1
} else if 'A' <= self.chr && self.chr <= 'Z' {
value = int64(self.chr) - 'A' + 1
} else {
err := self.goRegexp.WriteByte('c')
if err != nil {
self.errors = append(self.errors, err)
}
return
}
tmp := []byte{'\\', 'x', '0', 0}
if value >= 16 {
tmp = tmp[0:2]
} else {
tmp = tmp[0:3]
}
tmp = strconv.AppendInt(tmp, value, 16)
_, err := self.goRegexp.Write(tmp)
if err != nil {
self.errors = append(self.errors, err)
}
self.read()
return
default:
// $ is an identifier character, so we have to have
// a special case for it here
if self.chr == '$' || !isIdentifierPart(self.chr) {
// A non-identifier character needs escaping
err := self.goRegexp.WriteByte('\\')
if err != nil {
self.errors = append(self.errors, err)
}
} else {
// Unescape the character for re2
}
self.pass()
return
}
// Otherwise, we're a \u.... or \x...
valueOffset := self.chrOffset
var value uint32
{
length := length
for ; length > 0; length-- {
digit := uint32(digitValue(self.chr))
if digit >= base {
// Not a valid digit
goto skip
}
value = value*base + digit
self.read()
}
}
if length == 4 {
_, err := self.goRegexp.Write([]byte{
'\\',
'x',
'{',
self.str[valueOffset+0],
self.str[valueOffset+1],
self.str[valueOffset+2],
self.str[valueOffset+3],
'}',
})
if err != nil {
self.errors = append(self.errors, err)
}
} else if length == 2 {
_, err := self.goRegexp.Write([]byte{
'\\',
'x',
self.str[valueOffset+0],
self.str[valueOffset+1],
})
if err != nil {
self.errors = append(self.errors, err)
}
} else {
// Should never, ever get here...
self.error(-1, "re2: Illegal branch in scanEscape")
goto skip
}
return
skip:
_, err := self.goRegexp.WriteString(self.str[offset:self.chrOffset])
if err != nil {
self.errors = append(self.errors, err)
}
}
func (self *_RegExp_parser) pass() {
if self.chr != -1 {
_, err := self.goRegexp.WriteRune(self.chr)
if err != nil {
self.errors = append(self.errors, err)
}
}
self.read()
}
// TODO Better error reporting, use the offset, etc.
func (self *_RegExp_parser) error(offset int, msg string, msgValues ...interface{}) error {
err := fmt.Errorf(msg, msgValues...)
self.errors = append(self.errors, err)
return err
}

View file

@ -1,149 +0,0 @@
package parser
import (
"regexp"
"testing"
)
func TestRegExp(t *testing.T) {
tt(t, func() {
{
// err
test := func(input string, expect interface{}) {
_, err := TransformRegExp(input)
is(err, expect)
}
test("[", "Unterminated character class")
test("(", "Unterminated group")
test("(?=)", "re2: Invalid (?=) <lookahead>")
test("(?=)", "re2: Invalid (?=) <lookahead>")
test("(?!)", "re2: Invalid (?!) <lookahead>")
// An error anyway
test("(?=", "re2: Invalid (?=) <lookahead>")
test("\\1", "re2: Invalid \\1 <backreference>")
test("\\90", "re2: Invalid \\90 <backreference>")
test("\\9123456789", "re2: Invalid \\9123456789 <backreference>")
test("\\(?=)", "Unmatched ')'")
test(")", "Unmatched ')'")
}
{
// err
test := func(input, expect string, expectErr interface{}) {
output, err := TransformRegExp(input)
is(output, expect)
is(err, expectErr)
}
test("(?!)", "(?!)", "re2: Invalid (?!) <lookahead>")
test(")", "", "Unmatched ')'")
test("(?!))", "", "re2: Invalid (?!) <lookahead>")
test("\\0", "\\0", nil)
test("\\1", "\\1", "re2: Invalid \\1 <backreference>")
test("\\9123456789", "\\9123456789", "re2: Invalid \\9123456789 <backreference>")
}
{
// err
test := func(input string, expect string) {
result, err := TransformRegExp(input)
is(err, nil)
if is(result, expect) {
_, err := regexp.Compile(result)
if !is(err, nil) {
t.Log(result)
}
}
}
test("", "")
test("abc", "abc")
test(`\abc`, `abc`)
test(`\a\b\c`, `a\bc`)
test(`\x`, `x`)
test(`\c`, `c`)
test(`\cA`, `\x01`)
test(`\cz`, `\x1a`)
test(`\ca`, `\x01`)
test(`\cj`, `\x0a`)
test(`\ck`, `\x0b`)
test(`\+`, `\+`)
test(`[\b]`, `[\x08]`)
test(`\u0z01\x\undefined`, `u0z01xundefined`)
test(`\\|'|\r|\n|\t|\u2028|\u2029`, `\\|'|\r|\n|\t|\x{2028}|\x{2029}`)
test("]", "]")
test("}", "}")
test("%", "%")
test("(%)", "(%)")
test("(?:[%\\s])", "(?:[%\\s])")
test("[[]", "[[]")
test("\\101", "\\x41")
test("\\51", "\\x29")
test("\\051", "\\x29")
test("\\175", "\\x7d")
test("\\04", "\\x04")
test(`<%([\s\S]+?)%>`, `<%([\s\S]+?)%>`)
test(`(.)^`, "(.)^")
test(`<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`, `<%-([\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$`)
test(`\$`, `\$`)
test(`[G-b]`, `[G-b]`)
test(`[G-b\0]`, `[G-b\0]`)
}
})
}
func TestTransformRegExp(t *testing.T) {
tt(t, func() {
pattern, err := TransformRegExp(`\s+abc\s+`)
is(err, nil)
is(pattern, `\s+abc\s+`)
is(regexp.MustCompile(pattern).MatchString("\t abc def"), true)
})
}

View file

@ -1,44 +0,0 @@
package parser
import (
"github.com/robertkrimen/otto/ast"
)
type _scope struct {
outer *_scope
allowIn bool
inIteration bool
inSwitch bool
inFunction bool
declarationList []ast.Declaration
labels []string
}
func (self *_parser) openScope() {
self.scope = &_scope{
outer: self.scope,
allowIn: true,
}
}
func (self *_parser) closeScope() {
self.scope = self.scope.outer
}
func (self *_scope) declare(declaration ast.Declaration) {
self.declarationList = append(self.declarationList, declaration)
}
func (self *_scope) hasLabel(name string) bool {
for _, label := range self.labels {
if label == name {
return true
}
}
if self.outer != nil && !self.inFunction {
// Crossing a function boundary to look for a label is verboten
return self.outer.hasLabel(name)
}
return false
}

View file

@ -1,662 +0,0 @@
package parser
import (
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/token"
)
func (self *_parser) parseBlockStatement() *ast.BlockStatement {
node := &ast.BlockStatement{}
node.LeftBrace = self.expect(token.LEFT_BRACE)
node.List = self.parseStatementList()
node.RightBrace = self.expect(token.RIGHT_BRACE)
return node
}
func (self *_parser) parseEmptyStatement() ast.Statement {
idx := self.expect(token.SEMICOLON)
return &ast.EmptyStatement{Semicolon: idx}
}
func (self *_parser) parseStatementList() (list []ast.Statement) {
for self.token != token.RIGHT_BRACE && self.token != token.EOF {
list = append(list, self.parseStatement())
}
return
}
func (self *_parser) parseStatement() ast.Statement {
if self.token == token.EOF {
self.errorUnexpectedToken(self.token)
return &ast.BadStatement{From: self.idx, To: self.idx + 1}
}
switch self.token {
case token.SEMICOLON:
return self.parseEmptyStatement()
case token.LEFT_BRACE:
return self.parseBlockStatement()
case token.IF:
return self.parseIfStatement()
case token.DO:
return self.parseDoWhileStatement()
case token.WHILE:
return self.parseWhileStatement()
case token.FOR:
return self.parseForOrForInStatement()
case token.BREAK:
return self.parseBreakStatement()
case token.CONTINUE:
return self.parseContinueStatement()
case token.DEBUGGER:
return self.parseDebuggerStatement()
case token.WITH:
return self.parseWithStatement()
case token.VAR:
return self.parseVariableStatement()
case token.FUNCTION:
self.parseFunction(true)
// FIXME
return &ast.EmptyStatement{}
case token.SWITCH:
return self.parseSwitchStatement()
case token.RETURN:
return self.parseReturnStatement()
case token.THROW:
return self.parseThrowStatement()
case token.TRY:
return self.parseTryStatement()
}
expression := self.parseExpression()
if identifier, isIdentifier := expression.(*ast.Identifier); isIdentifier && self.token == token.COLON {
// LabelledStatement
colon := self.idx
self.next() // :
label := identifier.Name
for _, value := range self.scope.labels {
if label == value {
self.error(identifier.Idx0(), "Label '%s' already exists", label)
}
}
self.scope.labels = append(self.scope.labels, label) // Push the label
statement := self.parseStatement()
self.scope.labels = self.scope.labels[:len(self.scope.labels)-1] // Pop the label
return &ast.LabelledStatement{
Label: identifier,
Colon: colon,
Statement: statement,
}
}
self.optionalSemicolon()
return &ast.ExpressionStatement{
Expression: expression,
}
}
func (self *_parser) parseTryStatement() ast.Statement {
node := &ast.TryStatement{
Try: self.expect(token.TRY),
Body: self.parseBlockStatement(),
}
if self.token == token.CATCH {
catch := self.idx
self.next()
self.expect(token.LEFT_PARENTHESIS)
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
self.nextStatement()
return &ast.BadStatement{From: catch, To: self.idx}
} else {
identifier := self.parseIdentifier()
self.expect(token.RIGHT_PARENTHESIS)
node.Catch = &ast.CatchStatement{
Catch: catch,
Parameter: identifier,
Body: self.parseBlockStatement(),
}
}
}
if self.token == token.FINALLY {
self.next()
node.Finally = self.parseBlockStatement()
}
if node.Catch == nil && node.Finally == nil {
self.error(node.Try, "Missing catch or finally after try")
return &ast.BadStatement{From: node.Try, To: node.Body.Idx1()}
}
return node
}
func (self *_parser) parseFunctionParameterList() *ast.ParameterList {
opening := self.expect(token.LEFT_PARENTHESIS)
var list []*ast.Identifier
for self.token != token.RIGHT_PARENTHESIS && self.token != token.EOF {
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
} else {
list = append(list, self.parseIdentifier())
}
if self.token != token.RIGHT_PARENTHESIS {
self.expect(token.COMMA)
}
}
closing := self.expect(token.RIGHT_PARENTHESIS)
return &ast.ParameterList{
Opening: opening,
List: list,
Closing: closing,
}
}
func (self *_parser) parseParameterList() (list []string) {
for self.token != token.EOF {
if self.token != token.IDENTIFIER {
self.expect(token.IDENTIFIER)
}
list = append(list, self.literal)
self.next()
if self.token != token.EOF {
self.expect(token.COMMA)
}
}
return
}
func (self *_parser) parseFunction(declaration bool) *ast.FunctionLiteral {
node := &ast.FunctionLiteral{
Function: self.expect(token.FUNCTION),
}
var name *ast.Identifier
if self.token == token.IDENTIFIER {
name = self.parseIdentifier()
if declaration {
self.scope.declare(&ast.FunctionDeclaration{
Function: node,
})
}
} else if declaration {
// Use expect error handling
self.expect(token.IDENTIFIER)
}
node.Name = name
node.ParameterList = self.parseFunctionParameterList()
self.parseFunctionBlock(node)
node.Source = self.slice(node.Idx0(), node.Idx1())
return node
}
func (self *_parser) parseFunctionBlock(node *ast.FunctionLiteral) {
{
self.openScope()
inFunction := self.scope.inFunction
self.scope.inFunction = true
defer func() {
self.scope.inFunction = inFunction
self.closeScope()
}()
node.Body = self.parseBlockStatement()
node.DeclarationList = self.scope.declarationList
}
}
func (self *_parser) parseDebuggerStatement() ast.Statement {
idx := self.expect(token.DEBUGGER)
node := &ast.DebuggerStatement{
Debugger: idx,
}
self.semicolon()
return node
}
func (self *_parser) parseReturnStatement() ast.Statement {
idx := self.expect(token.RETURN)
if !self.scope.inFunction {
self.error(idx, "Illegal return statement")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
node := &ast.ReturnStatement{
Return: idx,
}
if !self.implicitSemicolon && self.token != token.SEMICOLON && self.token != token.RIGHT_BRACE && self.token != token.EOF {
node.Argument = self.parseExpression()
}
self.semicolon()
return node
}
func (self *_parser) parseThrowStatement() ast.Statement {
idx := self.expect(token.THROW)
if self.implicitSemicolon {
if self.chr == -1 { // Hackish
self.error(idx, "Unexpected end of input")
} else {
self.error(idx, "Illegal newline after throw")
}
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
node := &ast.ThrowStatement{
Argument: self.parseExpression(),
}
self.semicolon()
return node
}
func (self *_parser) parseSwitchStatement() ast.Statement {
self.expect(token.SWITCH)
self.expect(token.LEFT_PARENTHESIS)
node := &ast.SwitchStatement{
Discriminant: self.parseExpression(),
Default: -1,
}
self.expect(token.RIGHT_PARENTHESIS)
self.expect(token.LEFT_BRACE)
inSwitch := self.scope.inSwitch
self.scope.inSwitch = true
defer func() {
self.scope.inSwitch = inSwitch
}()
for index := 0; self.token != token.EOF; index++ {
if self.token == token.RIGHT_BRACE {
self.next()
break
}
clause := self.parseCaseStatement()
if clause.Test == nil {
if node.Default != -1 {
self.error(clause.Case, "Already saw a default in switch")
}
node.Default = index
}
node.Body = append(node.Body, clause)
}
return node
}
func (self *_parser) parseWithStatement() ast.Statement {
self.expect(token.WITH)
self.expect(token.LEFT_PARENTHESIS)
node := &ast.WithStatement{
Object: self.parseExpression(),
}
self.expect(token.RIGHT_PARENTHESIS)
node.Body = self.parseStatement()
return node
}
func (self *_parser) parseCaseStatement() *ast.CaseStatement {
node := &ast.CaseStatement{
Case: self.idx,
}
if self.token == token.DEFAULT {
self.next()
} else {
self.expect(token.CASE)
node.Test = self.parseExpression()
}
self.expect(token.COLON)
for {
if self.token == token.EOF ||
self.token == token.RIGHT_BRACE ||
self.token == token.CASE ||
self.token == token.DEFAULT {
break
}
node.Consequent = append(node.Consequent, self.parseStatement())
}
return node
}
func (self *_parser) parseIterationStatement() ast.Statement {
inIteration := self.scope.inIteration
self.scope.inIteration = true
defer func() {
self.scope.inIteration = inIteration
}()
return self.parseStatement()
}
func (self *_parser) parseForIn(into ast.Expression) *ast.ForInStatement {
// Already have consumed "<into> in"
source := self.parseExpression()
self.expect(token.RIGHT_PARENTHESIS)
return &ast.ForInStatement{
Into: into,
Source: source,
Body: self.parseIterationStatement(),
}
}
func (self *_parser) parseFor(initializer ast.Expression) *ast.ForStatement {
// Already have consumed "<initializer> ;"
var test, update ast.Expression
if self.token != token.SEMICOLON {
test = self.parseExpression()
}
self.expect(token.SEMICOLON)
if self.token != token.RIGHT_PARENTHESIS {
update = self.parseExpression()
}
self.expect(token.RIGHT_PARENTHESIS)
return &ast.ForStatement{
Initializer: initializer,
Test: test,
Update: update,
Body: self.parseIterationStatement(),
}
}
func (self *_parser) parseForOrForInStatement() ast.Statement {
idx := self.expect(token.FOR)
self.expect(token.LEFT_PARENTHESIS)
var left []ast.Expression
forIn := false
if self.token != token.SEMICOLON {
allowIn := self.scope.allowIn
self.scope.allowIn = false
if self.token == token.VAR {
var_ := self.idx
self.next()
list := self.parseVariableDeclarationList(var_)
if len(list) == 1 && self.token == token.IN {
self.next() // in
forIn = true
left = []ast.Expression{list[0]} // There is only one declaration
} else {
left = list
}
} else {
left = append(left, self.parseExpression())
if self.token == token.IN {
self.next()
forIn = true
}
}
self.scope.allowIn = allowIn
}
if forIn {
switch left[0].(type) {
case *ast.Identifier, *ast.DotExpression, *ast.BracketExpression, *ast.VariableExpression:
// These are all acceptable
default:
self.error(idx, "Invalid left-hand side in for-in")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
return self.parseForIn(left[0])
}
self.expect(token.SEMICOLON)
return self.parseFor(&ast.SequenceExpression{Sequence: left})
}
func (self *_parser) parseVariableStatement() *ast.VariableStatement {
idx := self.expect(token.VAR)
list := self.parseVariableDeclarationList(idx)
self.semicolon()
return &ast.VariableStatement{
Var: idx,
List: list,
}
}
func (self *_parser) parseDoWhileStatement() ast.Statement {
inIteration := self.scope.inIteration
self.scope.inIteration = true
defer func() {
self.scope.inIteration = inIteration
}()
self.expect(token.DO)
node := &ast.DoWhileStatement{}
if self.token == token.LEFT_BRACE {
node.Body = self.parseBlockStatement()
} else {
node.Body = self.parseStatement()
}
self.expect(token.WHILE)
self.expect(token.LEFT_PARENTHESIS)
node.Test = self.parseExpression()
self.expect(token.RIGHT_PARENTHESIS)
return node
}
func (self *_parser) parseWhileStatement() ast.Statement {
self.expect(token.WHILE)
self.expect(token.LEFT_PARENTHESIS)
node := &ast.WhileStatement{
Test: self.parseExpression(),
}
self.expect(token.RIGHT_PARENTHESIS)
node.Body = self.parseIterationStatement()
return node
}
func (self *_parser) parseIfStatement() ast.Statement {
self.expect(token.IF)
self.expect(token.LEFT_PARENTHESIS)
node := &ast.IfStatement{
Test: self.parseExpression(),
}
self.expect(token.RIGHT_PARENTHESIS)
if self.token == token.LEFT_BRACE {
node.Consequent = self.parseBlockStatement()
} else {
node.Consequent = self.parseStatement()
}
if self.token == token.ELSE {
self.next()
node.Alternate = self.parseStatement()
}
return node
}
func (self *_parser) parseSourceElement() ast.Statement {
return self.parseStatement()
}
func (self *_parser) parseSourceElements() []ast.Statement {
body := []ast.Statement(nil)
for {
if self.token != token.STRING {
break
}
body = append(body, self.parseSourceElement())
}
for self.token != token.EOF {
body = append(body, self.parseSourceElement())
}
return body
}
func (self *_parser) parseProgram() *ast.Program {
self.openScope()
defer self.closeScope()
return &ast.Program{
Body: self.parseSourceElements(),
DeclarationList: self.scope.declarationList,
}
}
func (self *_parser) parseBreakStatement() ast.Statement {
idx := self.expect(token.BREAK)
semicolon := self.implicitSemicolon
if self.token == token.SEMICOLON {
semicolon = true
self.next()
}
if semicolon || self.token == token.RIGHT_BRACE {
self.implicitSemicolon = false
if !self.scope.inIteration && !self.scope.inSwitch {
goto illegal
}
return &ast.BranchStatement{
Idx: idx,
Token: token.BREAK,
}
}
if self.token == token.IDENTIFIER {
identifier := self.parseIdentifier()
if !self.scope.hasLabel(identifier.Name) {
self.error(idx, "Undefined label '%s'", identifier.Name)
return &ast.BadStatement{From: idx, To: identifier.Idx1()}
}
self.semicolon()
return &ast.BranchStatement{
Idx: idx,
Token: token.BREAK,
Label: identifier,
}
}
self.expect(token.IDENTIFIER)
illegal:
self.error(idx, "Illegal break statement")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
func (self *_parser) parseContinueStatement() ast.Statement {
idx := self.expect(token.CONTINUE)
semicolon := self.implicitSemicolon
if self.token == token.SEMICOLON {
semicolon = true
self.next()
}
if semicolon || self.token == token.RIGHT_BRACE {
self.implicitSemicolon = false
if !self.scope.inIteration {
goto illegal
}
return &ast.BranchStatement{
Idx: idx,
Token: token.CONTINUE,
}
}
if self.token == token.IDENTIFIER {
identifier := self.parseIdentifier()
if !self.scope.hasLabel(identifier.Name) {
self.error(idx, "Undefined label '%s'", identifier.Name)
return &ast.BadStatement{From: idx, To: identifier.Idx1()}
}
if !self.scope.inIteration {
goto illegal
}
self.semicolon()
return &ast.BranchStatement{
Idx: idx,
Token: token.CONTINUE,
Label: identifier,
}
}
self.expect(token.IDENTIFIER)
illegal:
self.error(idx, "Illegal continue statement")
self.nextStatement()
return &ast.BadStatement{From: idx, To: self.idx}
}
// Find the next statement after an error (recover)
func (self *_parser) nextStatement() {
for {
switch self.token {
case token.BREAK, token.CONTINUE,
token.FOR, token.IF, token.RETURN, token.SWITCH,
token.VAR, token.DO, token.TRY, token.WITH,
token.WHILE, token.THROW, token.CATCH, token.FINALLY:
// Return only if parser made some progress since last
// sync or if it has not reached 10 next calls without
// progress. Otherwise consume at least one token to
// avoid an endless parser loop
if self.idx == self.recover.idx && self.recover.count < 10 {
self.recover.count++
return
}
if self.idx > self.recover.idx {
self.recover.idx = self.idx
self.recover.count = 0
return
}
// Reaching here indicates a parser bug, likely an
// incorrect token list in this function, but it only
// leads to skipping of possibly correct code if a
// previous error is present, and thus is preferred
// over a non-terminating parse.
case token.EOF:
return
}
self.next()
}
}

View file

@ -1,51 +0,0 @@
# registry
--
import "github.com/robertkrimen/otto/registry"
Package registry is an expirmental package to facillitate altering the otto
runtime via import.
This interface can change at any time.
## Usage
#### func Apply
```go
func Apply(callback func(Entry))
```
#### type Entry
```go
type Entry struct {
}
```
#### func Register
```go
func Register(source func() string) *Entry
```
#### func (*Entry) Disable
```go
func (self *Entry) Disable()
```
#### func (*Entry) Enable
```go
func (self *Entry) Enable()
```
#### func (Entry) Source
```go
func (self Entry) Source() string
```
--
**godocdown** http://github.com/robertkrimen/godocdown

View file

@ -1,47 +0,0 @@
/*
Package registry is an expirmental package to facillitate altering the otto runtime via import.
This interface can change at any time.
*/
package registry
var registry []*Entry = make([]*Entry, 0)
type Entry struct {
active bool
source func() string
}
func newEntry(source func() string) *Entry {
return &Entry{
active: true,
source: source,
}
}
func (self *Entry) Enable() {
self.active = true
}
func (self *Entry) Disable() {
self.active = false
}
func (self Entry) Source() string {
return self.source()
}
func Apply(callback func(Entry)) {
for _, entry := range registry {
if !entry.active {
continue
}
callback(*entry)
}
}
func Register(source func() string) *Entry {
entry := newEntry(source)
registry = append(registry, entry)
return entry
}

View file

@ -1,2 +0,0 @@
token_const.go: tokenfmt
./$^ | gofmt > $@

View file

@ -1,171 +0,0 @@
# token
--
import "github.com/robertkrimen/otto/token"
Package token defines constants representing the lexical tokens of JavaScript
(ECMA5).
## Usage
```go
const (
ILLEGAL
EOF
COMMENT
KEYWORD
STRING
BOOLEAN
NULL
NUMBER
IDENTIFIER
PLUS // +
MINUS // -
MULTIPLY // *
SLASH // /
REMAINDER // %
AND // &
OR // |
EXCLUSIVE_OR // ^
SHIFT_LEFT // <<
SHIFT_RIGHT // >>
UNSIGNED_SHIFT_RIGHT // >>>
AND_NOT // &^
ADD_ASSIGN // +=
SUBTRACT_ASSIGN // -=
MULTIPLY_ASSIGN // *=
QUOTIENT_ASSIGN // /=
REMAINDER_ASSIGN // %=
AND_ASSIGN // &=
OR_ASSIGN // |=
EXCLUSIVE_OR_ASSIGN // ^=
SHIFT_LEFT_ASSIGN // <<=
SHIFT_RIGHT_ASSIGN // >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>=
AND_NOT_ASSIGN // &^=
LOGICAL_AND // &&
LOGICAL_OR // ||
INCREMENT // ++
DECREMENT // --
EQUAL // ==
STRICT_EQUAL // ===
LESS // <
GREATER // >
ASSIGN // =
NOT // !
BITWISE_NOT // ~
NOT_EQUAL // !=
STRICT_NOT_EQUAL // !==
LESS_OR_EQUAL // <=
GREATER_OR_EQUAL // <=
LEFT_PARENTHESIS // (
LEFT_BRACKET // [
LEFT_BRACE // {
COMMA // ,
PERIOD // .
RIGHT_PARENTHESIS // )
RIGHT_BRACKET // ]
RIGHT_BRACE // }
SEMICOLON // ;
COLON // :
QUESTION_MARK // ?
IF
IN
DO
VAR
FOR
NEW
TRY
THIS
ELSE
CASE
VOID
WITH
WHILE
BREAK
CATCH
THROW
RETURN
TYPEOF
DELETE
SWITCH
DEFAULT
FINALLY
FUNCTION
CONTINUE
DEBUGGER
INSTANCEOF
)
```
#### type Token
```go
type Token int
```
Token is the set of lexical tokens in JavaScript (ECMA5).
#### func IsKeyword
```go
func IsKeyword(literal string) (Token, bool)
```
IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token if
the literal is a future keyword (const, let, class, super, ...), or 0 if the
literal is not a keyword.
If the literal is a keyword, IsKeyword returns a second value indicating if the
literal is considered a future keyword in strict-mode only.
7.6.1.2 Future Reserved Words:
const
class
enum
export
extends
import
super
7.6.1.2 Future Reserved Words (strict):
implements
interface
let
package
private
protected
public
static
#### func (Token) String
```go
func (tkn Token) String() string
```
String returns the string corresponding to the token. For operators, delimiters,
and keywords the string is the actual token string (e.g., for the token PLUS,
the String() is "+"). For all other tokens the string corresponds to the token
name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER").
--
**godocdown** http://github.com/robertkrimen/godocdown

View file

@ -1,116 +0,0 @@
// Package token defines constants representing the lexical tokens of JavaScript (ECMA5).
package token
import (
"strconv"
)
// Token is the set of lexical tokens in JavaScript (ECMA5).
type Token int
// String returns the string corresponding to the token.
// For operators, delimiters, and keywords the string is the actual
// token string (e.g., for the token PLUS, the String() is
// "+"). For all other tokens the string corresponds to the token
// name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER").
//
func (tkn Token) String() string {
if 0 == tkn {
return "UNKNOWN"
}
if tkn < Token(len(token2string)) {
return token2string[tkn]
}
return "token(" + strconv.Itoa(int(tkn)) + ")"
}
// This is not used for anything
func (tkn Token) precedence(in bool) int {
switch tkn {
case LOGICAL_OR:
return 1
case LOGICAL_AND:
return 2
case OR, OR_ASSIGN:
return 3
case EXCLUSIVE_OR:
return 4
case AND, AND_ASSIGN, AND_NOT, AND_NOT_ASSIGN:
return 5
case EQUAL,
NOT_EQUAL,
STRICT_EQUAL,
STRICT_NOT_EQUAL:
return 6
case LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL, INSTANCEOF:
return 7
case IN:
if in {
return 7
}
return 0
case SHIFT_LEFT, SHIFT_RIGHT, UNSIGNED_SHIFT_RIGHT:
fallthrough
case SHIFT_LEFT_ASSIGN, SHIFT_RIGHT_ASSIGN, UNSIGNED_SHIFT_RIGHT_ASSIGN:
return 8
case PLUS, MINUS, ADD_ASSIGN, SUBTRACT_ASSIGN:
return 9
case MULTIPLY, SLASH, REMAINDER, MULTIPLY_ASSIGN, QUOTIENT_ASSIGN, REMAINDER_ASSIGN:
return 11
}
return 0
}
type _keyword struct {
token Token
futureKeyword bool
strict bool
}
// IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token
// if the literal is a future keyword (const, let, class, super, ...), or 0 if the literal is not a keyword.
//
// If the literal is a keyword, IsKeyword returns a second value indicating if the literal
// is considered a future keyword in strict-mode only.
//
// 7.6.1.2 Future Reserved Words:
//
// const
// class
// enum
// export
// extends
// import
// super
//
// 7.6.1.2 Future Reserved Words (strict):
//
// implements
// interface
// let
// package
// private
// protected
// public
// static
//
func IsKeyword(literal string) (Token, bool) {
if keyword, exists := keywordTable[literal]; exists {
if keyword.futureKeyword {
return KEYWORD, keyword.strict
}
return keyword.token, false
}
return 0, false
}

View file

@ -1,349 +0,0 @@
package token
const (
_ Token = iota
ILLEGAL
EOF
COMMENT
KEYWORD
STRING
BOOLEAN
NULL
NUMBER
IDENTIFIER
PLUS // +
MINUS // -
MULTIPLY // *
SLASH // /
REMAINDER // %
AND // &
OR // |
EXCLUSIVE_OR // ^
SHIFT_LEFT // <<
SHIFT_RIGHT // >>
UNSIGNED_SHIFT_RIGHT // >>>
AND_NOT // &^
ADD_ASSIGN // +=
SUBTRACT_ASSIGN // -=
MULTIPLY_ASSIGN // *=
QUOTIENT_ASSIGN // /=
REMAINDER_ASSIGN // %=
AND_ASSIGN // &=
OR_ASSIGN // |=
EXCLUSIVE_OR_ASSIGN // ^=
SHIFT_LEFT_ASSIGN // <<=
SHIFT_RIGHT_ASSIGN // >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>=
AND_NOT_ASSIGN // &^=
LOGICAL_AND // &&
LOGICAL_OR // ||
INCREMENT // ++
DECREMENT // --
EQUAL // ==
STRICT_EQUAL // ===
LESS // <
GREATER // >
ASSIGN // =
NOT // !
BITWISE_NOT // ~
NOT_EQUAL // !=
STRICT_NOT_EQUAL // !==
LESS_OR_EQUAL // <=
GREATER_OR_EQUAL // <=
LEFT_PARENTHESIS // (
LEFT_BRACKET // [
LEFT_BRACE // {
COMMA // ,
PERIOD // .
RIGHT_PARENTHESIS // )
RIGHT_BRACKET // ]
RIGHT_BRACE // }
SEMICOLON // ;
COLON // :
QUESTION_MARK // ?
firstKeyword
IF
IN
DO
VAR
FOR
NEW
TRY
THIS
ELSE
CASE
VOID
WITH
WHILE
BREAK
CATCH
THROW
RETURN
TYPEOF
DELETE
SWITCH
DEFAULT
FINALLY
FUNCTION
CONTINUE
DEBUGGER
INSTANCEOF
lastKeyword
)
var token2string = [...]string{
ILLEGAL: "ILLEGAL",
EOF: "EOF",
COMMENT: "COMMENT",
KEYWORD: "KEYWORD",
STRING: "STRING",
BOOLEAN: "BOOLEAN",
NULL: "NULL",
NUMBER: "NUMBER",
IDENTIFIER: "IDENTIFIER",
PLUS: "+",
MINUS: "-",
MULTIPLY: "*",
SLASH: "/",
REMAINDER: "%",
AND: "&",
OR: "|",
EXCLUSIVE_OR: "^",
SHIFT_LEFT: "<<",
SHIFT_RIGHT: ">>",
UNSIGNED_SHIFT_RIGHT: ">>>",
AND_NOT: "&^",
ADD_ASSIGN: "+=",
SUBTRACT_ASSIGN: "-=",
MULTIPLY_ASSIGN: "*=",
QUOTIENT_ASSIGN: "/=",
REMAINDER_ASSIGN: "%=",
AND_ASSIGN: "&=",
OR_ASSIGN: "|=",
EXCLUSIVE_OR_ASSIGN: "^=",
SHIFT_LEFT_ASSIGN: "<<=",
SHIFT_RIGHT_ASSIGN: ">>=",
UNSIGNED_SHIFT_RIGHT_ASSIGN: ">>>=",
AND_NOT_ASSIGN: "&^=",
LOGICAL_AND: "&&",
LOGICAL_OR: "||",
INCREMENT: "++",
DECREMENT: "--",
EQUAL: "==",
STRICT_EQUAL: "===",
LESS: "<",
GREATER: ">",
ASSIGN: "=",
NOT: "!",
BITWISE_NOT: "~",
NOT_EQUAL: "!=",
STRICT_NOT_EQUAL: "!==",
LESS_OR_EQUAL: "<=",
GREATER_OR_EQUAL: "<=",
LEFT_PARENTHESIS: "(",
LEFT_BRACKET: "[",
LEFT_BRACE: "{",
COMMA: ",",
PERIOD: ".",
RIGHT_PARENTHESIS: ")",
RIGHT_BRACKET: "]",
RIGHT_BRACE: "}",
SEMICOLON: ";",
COLON: ":",
QUESTION_MARK: "?",
IF: "if",
IN: "in",
DO: "do",
VAR: "var",
FOR: "for",
NEW: "new",
TRY: "try",
THIS: "this",
ELSE: "else",
CASE: "case",
VOID: "void",
WITH: "with",
WHILE: "while",
BREAK: "break",
CATCH: "catch",
THROW: "throw",
RETURN: "return",
TYPEOF: "typeof",
DELETE: "delete",
SWITCH: "switch",
DEFAULT: "default",
FINALLY: "finally",
FUNCTION: "function",
CONTINUE: "continue",
DEBUGGER: "debugger",
INSTANCEOF: "instanceof",
}
var keywordTable = map[string]_keyword{
"if": _keyword{
token: IF,
},
"in": _keyword{
token: IN,
},
"do": _keyword{
token: DO,
},
"var": _keyword{
token: VAR,
},
"for": _keyword{
token: FOR,
},
"new": _keyword{
token: NEW,
},
"try": _keyword{
token: TRY,
},
"this": _keyword{
token: THIS,
},
"else": _keyword{
token: ELSE,
},
"case": _keyword{
token: CASE,
},
"void": _keyword{
token: VOID,
},
"with": _keyword{
token: WITH,
},
"while": _keyword{
token: WHILE,
},
"break": _keyword{
token: BREAK,
},
"catch": _keyword{
token: CATCH,
},
"throw": _keyword{
token: THROW,
},
"return": _keyword{
token: RETURN,
},
"typeof": _keyword{
token: TYPEOF,
},
"delete": _keyword{
token: DELETE,
},
"switch": _keyword{
token: SWITCH,
},
"default": _keyword{
token: DEFAULT,
},
"finally": _keyword{
token: FINALLY,
},
"function": _keyword{
token: FUNCTION,
},
"continue": _keyword{
token: CONTINUE,
},
"debugger": _keyword{
token: DEBUGGER,
},
"instanceof": _keyword{
token: INSTANCEOF,
},
"const": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"class": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"enum": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"export": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"extends": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"import": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"super": _keyword{
token: KEYWORD,
futureKeyword: true,
},
"implements": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"interface": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"let": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"package": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"private": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"protected": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"public": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"static": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
}

View file

@ -1,222 +0,0 @@
#!/usr/bin/env perl
use strict;
use warnings;
my (%token, @order, @keywords);
{
my $keywords;
my @const;
push @const, <<_END_;
package token
const(
_ Token = iota
_END_
for (split m/\n/, <<_END_) {
ILLEGAL
EOF
COMMENT
KEYWORD
STRING
BOOLEAN
NULL
NUMBER
IDENTIFIER
PLUS +
MINUS -
MULTIPLY *
SLASH /
REMAINDER %
AND &
OR |
EXCLUSIVE_OR ^
SHIFT_LEFT <<
SHIFT_RIGHT >>
UNSIGNED_SHIFT_RIGHT >>>
AND_NOT &^
ADD_ASSIGN +=
SUBTRACT_ASSIGN -=
MULTIPLY_ASSIGN *=
QUOTIENT_ASSIGN /=
REMAINDER_ASSIGN %=
AND_ASSIGN &=
OR_ASSIGN |=
EXCLUSIVE_OR_ASSIGN ^=
SHIFT_LEFT_ASSIGN <<=
SHIFT_RIGHT_ASSIGN >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN >>>=
AND_NOT_ASSIGN &^=
LOGICAL_AND &&
LOGICAL_OR ||
INCREMENT ++
DECREMENT --
EQUAL ==
STRICT_EQUAL ===
LESS <
GREATER >
ASSIGN =
NOT !
BITWISE_NOT ~
NOT_EQUAL !=
STRICT_NOT_EQUAL !==
LESS_OR_EQUAL <=
GREATER_OR_EQUAL <=
LEFT_PARENTHESIS (
LEFT_BRACKET [
LEFT_BRACE {
COMMA ,
PERIOD .
RIGHT_PARENTHESIS )
RIGHT_BRACKET ]
RIGHT_BRACE }
SEMICOLON ;
COLON :
QUESTION_MARK ?
firstKeyword
IF
IN
DO
VAR
FOR
NEW
TRY
THIS
ELSE
CASE
VOID
WITH
WHILE
BREAK
CATCH
THROW
RETURN
TYPEOF
DELETE
SWITCH
DEFAULT
FINALLY
FUNCTION
CONTINUE
DEBUGGER
INSTANCEOF
lastKeyword
_END_
chomp;
next if m/^\s*#/;
my ($name, $symbol) = m/(\w+)\s*(\S+)?/;
if (defined $symbol) {
push @order, $name;
push @const, "$name // $symbol";
$token{$name} = $symbol;
} elsif (defined $name) {
$keywords ||= $name eq 'firstKeyword';
push @const, $name;
#$const[-1] .= " Token = iota" if 2 == @const;
if ($name =~ m/^([A-Z]+)/) {
push @keywords, $name if $keywords;
push @order, $name;
if ($token{SEMICOLON}) {
$token{$name} = lc $1;
} else {
$token{$name} = $name;
}
}
} else {
push @const, "";
}
}
push @const, ")";
print join "\n", @const, "";
}
{
print <<_END_;
var token2string = [...]string{
_END_
for my $name (@order) {
print "$name: \"$token{$name}\",\n";
}
print <<_END_;
}
_END_
print <<_END_;
var keywordTable = map[string]_keyword{
_END_
for my $name (@keywords) {
print <<_END_
"@{[ lc $name ]}": _keyword{
token: $name,
},
_END_
}
for my $name (qw/
const
class
enum
export
extends
import
super
/) {
print <<_END_
"$name": _keyword{
token: KEYWORD,
futureKeyword: true,
},
_END_
}
for my $name (qw/
implements
interface
let
package
private
protected
public
static
/) {
print <<_END_
"$name": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
_END_
}
print <<_END_;
}
_END_
}

View file

@ -1,9 +0,0 @@
package otto
func (runtime *_runtime) newErrorObject(message Value) *_object {
self := runtime.newClassObject("Error")
if message.IsDefined() {
self.defineProperty("message", toValue_string(toString(message)), 0111, false)
}
return self
}

View file

@ -1,276 +0,0 @@
package otto
import (
"fmt"
)
type _functionObject struct {
call _callFunction
construct _constructFunction
}
func (self _functionObject) source(object *_object) string {
return self.call.Source(object)
}
func (self0 _functionObject) clone(clone *_clone) _functionObject {
return _functionObject{
clone.callFunction(self0.call),
self0.construct,
}
}
func (runtime *_runtime) newNativeFunctionObject(name string, native _nativeFunction, length int) *_object {
self := runtime.newClassObject("Function")
self.value = _functionObject{
call: newNativeCallFunction(native),
construct: defaultConstructFunction,
}
self.defineProperty("length", toValue_int(length), 0000, false)
return self
}
func (runtime *_runtime) newBoundFunctionObject(target *_object, this Value, argumentList []Value) *_object {
self := runtime.newClassObject("Function")
self.value = _functionObject{
call: newBoundCallFunction(target, this, argumentList),
construct: newBoundConstructFunction(target),
}
length := int(toInt32(target.get("length")))
length -= len(argumentList)
if length < 0 {
length = 0
}
self.defineProperty("length", toValue_int(length), 0000, false)
self.defineProperty("caller", UndefinedValue(), 0000, false) // TODO Should throw a TypeError
self.defineProperty("arguments", UndefinedValue(), 0000, false) // TODO Should throw a TypeError
return self
}
func (runtime *_runtime) newBoundFunction(target *_object, this Value, argumentList []Value) *_object {
self := runtime.newBoundFunctionObject(target, this, argumentList)
self.prototype = runtime.Global.FunctionPrototype
prototype := runtime.newObject()
self.defineProperty("prototype", toValue_object(prototype), 0100, false)
prototype.defineProperty("constructor", toValue_object(self), 0100, false)
return self
}
func (self *_object) functionValue() _functionObject {
value, _ := self.value.(_functionObject)
return value
}
func (self *_object) Call(this Value, argumentList ...interface{}) Value {
if self.functionValue().call == nil {
panic(newTypeError("%v is not a function", toValue_object(self)))
}
return self.runtime.Call(self, this, self.runtime.toValueArray(argumentList...), false)
// ... -> runtime -> self.Function.Call.Dispatch -> ...
}
func (self *_object) Construct(this Value, argumentList ...interface{}) Value {
function := self.functionValue()
if function.call == nil {
panic(newTypeError("%v is not a function", toValue_object(self)))
}
if function.construct == nil {
panic(newTypeError("%v is not a constructor", toValue_object(self)))
}
return function.construct(self, this, self.runtime.toValueArray(argumentList...))
}
func defaultConstructFunction(self *_object, this Value, argumentList []Value) Value {
newObject := self.runtime.newObject()
newObject.class = "Object"
prototypeValue := self.get("prototype")
if !prototypeValue.IsObject() {
prototypeValue = toValue_object(self.runtime.Global.ObjectPrototype)
}
newObject.prototype = prototypeValue._object()
newObjectValue := toValue_object(newObject)
result := self.Call(newObjectValue, argumentList)
if result.IsObject() {
return result
}
return newObjectValue
}
func (self *_object) callGet(this Value) Value {
return self.runtime.Call(self, this, []Value(nil), false)
}
func (self *_object) callSet(this Value, value Value) {
self.runtime.Call(self, this, []Value{value}, false)
}
// 15.3.5.3
func (self *_object) HasInstance(of Value) bool {
if self.functionValue().call == nil {
// We should not have a HasInstance method
panic(newTypeError())
}
if !of.IsObject() {
return false
}
prototype := self.get("prototype")
if !prototype.IsObject() {
panic(newTypeError())
}
prototypeObject := prototype._object()
value := of._object().prototype
for value != nil {
if value == prototypeObject {
return true
}
value = value.prototype
}
return false
}
type _nativeFunction func(FunctionCall) Value
// _constructFunction
type _constructFunction func(*_object, Value, []Value) Value
// _callFunction
type _callFunction interface {
Dispatch(*_object, *_functionEnvironment, *_runtime, Value, []Value, bool) Value
Source(*_object) string
ScopeEnvironment() _environment
clone(clone *_clone) _callFunction
}
// _nativeCallFunction
type _nativeCallFunction struct {
name string
function _nativeFunction
}
func newNativeCallFunction(native _nativeFunction) _nativeCallFunction {
return _nativeCallFunction{"", native}
}
func (self _nativeCallFunction) Dispatch(_ *_object, _ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, evalHint bool) Value {
return self.function(FunctionCall{
runtime: runtime,
evalHint: evalHint,
This: this,
ArgumentList: argumentList,
Otto: runtime.Otto,
})
}
func (self _nativeCallFunction) ScopeEnvironment() _environment {
return nil
}
func (self _nativeCallFunction) Source(*_object) string {
return fmt.Sprintf("function %s() { [native code] }", self.name)
}
func (self0 _nativeCallFunction) clone(clone *_clone) _callFunction {
return self0
}
// _boundCallFunction
type _boundCallFunction struct {
target *_object
this Value
argumentList []Value
}
func newBoundCallFunction(target *_object, this Value, argumentList []Value) *_boundCallFunction {
self := &_boundCallFunction{
target: target,
this: this,
argumentList: argumentList,
}
return self
}
func (self _boundCallFunction) Dispatch(_ *_object, _ *_functionEnvironment, runtime *_runtime, this Value, argumentList []Value, _ bool) Value {
argumentList = append(self.argumentList, argumentList...)
return runtime.Call(self.target, self.this, argumentList, false)
}
func (self _boundCallFunction) ScopeEnvironment() _environment {
return nil
}
func (self _boundCallFunction) Source(*_object) string {
return ""
}
func (self0 _boundCallFunction) clone(clone *_clone) _callFunction {
return _boundCallFunction{
target: clone.object(self0.target),
this: clone.value(self0.this),
argumentList: clone.valueArray(self0.argumentList),
}
}
func newBoundConstructFunction(target *_object) _constructFunction {
// This is not exactly as described in 15.3.4.5.2, we let [[Call]] supply the
// bound arguments, etc.
return func(self *_object, this Value, argumentList []Value) Value {
switch value := target.value.(type) {
case _functionObject:
return value.construct(self, this, argumentList)
}
panic(newTypeError())
}
}
// FunctionCall{}
// FunctionCall is an encapsulation of a JavaScript function call.
type FunctionCall struct {
runtime *_runtime
_thisObject *_object
evalHint bool
This Value
ArgumentList []Value
Otto *Otto
}
// Argument will return the value of the argument at the given index.
//
// If no such argument exists, undefined is returned.
func (self FunctionCall) Argument(index int) Value {
return valueOfArrayIndex(self.ArgumentList, index)
}
func (self FunctionCall) getArgument(index int) (Value, bool) {
return getValueOfArrayIndex(self.ArgumentList, index)
}
func (self FunctionCall) slice(index int) []Value {
if index < len(self.ArgumentList) {
return self.ArgumentList[index:]
}
return []Value{}
}
func (self *FunctionCall) thisObject() *_object {
if self._thisObject == nil {
this := self.runtime.GetValue(self.This) // FIXME Is this right?
self._thisObject = self.runtime.toObject(this)
}
return self._thisObject
}
func (self *FunctionCall) thisClassObject(class string) *_object {
thisObject := self.thisObject()
if thisObject.class != class {
panic(newTypeError())
}
return self._thisObject
}
func (self FunctionCall) toObject(value Value) *_object {
return self.runtime.toObject(value)
}

View file

@ -1,157 +0,0 @@
package otto
import (
"github.com/robertkrimen/otto/ast"
)
type _reference interface {
GetBase() interface{} // GetBase
GetName() string // GetReferencedName
IsStrict() bool // IsStrictReference
IsUnresolvable() bool // IsUnresolvableReference
IsPropertyReference() bool // IsPropertyReference
GetValue() Value // GetValue
PutValue(Value) bool // PutValue
Delete() bool
}
// Reference
type _referenceDefault struct {
name string
strict bool
}
func (self _referenceDefault) GetName() string {
return self.name
}
func (self _referenceDefault) IsStrict() bool {
return self.strict
}
// PropertyReference
type _propertyReference struct {
_referenceDefault
Base *_object
}
func newPropertyReference(base *_object, name string, strict bool) *_propertyReference {
return &_propertyReference{
Base: base,
_referenceDefault: _referenceDefault{
name: name,
strict: strict,
},
}
}
func (self *_propertyReference) GetBase() interface{} {
return self.Base
}
func (self *_propertyReference) IsUnresolvable() bool {
return self.Base == nil
}
func (self *_propertyReference) IsPropertyReference() bool {
return true
}
func (self *_propertyReference) GetValue() Value {
if self.Base == nil {
panic(newReferenceError("notDefined", self.name))
}
return self.Base.get(self.name)
}
func (self *_propertyReference) PutValue(value Value) bool {
if self.Base == nil {
return false
}
self.Base.put(self.name, value, self.IsStrict())
return true
}
func (self *_propertyReference) Delete() bool {
if self.Base == nil {
// TODO Throw an error if strict
return true
}
return self.Base.delete(self.name, self.IsStrict())
}
// ArgumentReference
func newArgumentReference(base *_object, name string, strict bool) *_propertyReference {
if base == nil {
panic(hereBeDragons())
}
return newPropertyReference(base, name, strict)
}
type _environmentReference struct {
_referenceDefault
Base _environment
node ast.Node
}
func newEnvironmentReference(base _environment, name string, strict bool, node ast.Node) *_environmentReference {
return &_environmentReference{
Base: base,
_referenceDefault: _referenceDefault{
name: name,
strict: strict,
},
node: node,
}
}
func (self *_environmentReference) GetBase() interface{} {
return self.Base
}
func (self *_environmentReference) IsUnresolvable() bool {
return self.Base == nil // The base (an environment) will never be nil
}
func (self *_environmentReference) IsPropertyReference() bool {
return false
}
func (self *_environmentReference) GetValue() Value {
if self.Base == nil {
// This should never be reached, but just in case
}
return self.Base.GetValue(self.name, self.IsStrict())
}
func (self *_environmentReference) PutValue(value Value) bool {
if self.Base == nil {
// This should never be reached, but just in case
return false
}
self.Base.SetValue(self.name, value, self.IsStrict())
return true
}
func (self *_environmentReference) Delete() bool {
if self.Base == nil {
// This should never be reached, but just in case
return false
}
return self.Base.DeleteBinding(self.name)
}
// getIdentifierReference
func getIdentifierReference(environment _environment, name string, strict bool) _reference {
if environment == nil {
return newPropertyReference(nil, name, strict)
}
if environment.HasBinding(name) {
return environment.newReference(name, strict)
}
return getIdentifierReference(environment.Outer(), name, strict)
}

View file

@ -6,8 +6,8 @@ TESTS := \
~
TEST := -v --run
TEST := -v --run Test\($(subst $(eval) ,\|,$(TESTS))\)
TEST := -v
TEST := -v --run Test\($(subst $(eval) ,\|,$(TESTS))\)
TEST := .
test: parser inline.go

View file

@ -60,7 +60,7 @@ Set a Go function
vm.Set("sayHello", func(call otto.FunctionCall) otto.Value {
fmt.Printf("Hello, %s.\n", call.Argument(0).String())
return otto.UndefinedValue()
return otto.Value{}
})
Set a Go function that returns something useful
@ -139,7 +139,6 @@ For more information: http://github.com/robertkrimen/otto/tree/master/underscore
The following are some limitations with otto:
* "use strict" will parse, but does nothing.
* Error reporting needs to be improved.
* The regular expression engine (re2/regexp) is not fully compatible with the ECMA5 specification.
@ -205,16 +204,18 @@ the interrupt channel to do this:
}
fmt.Fprintf(os.Stderr, "Ran code successfully: %v\n", duration)
}()
vm := otto.New()
vm.Interrupt = make(chan func())
vm.Interrupt = make(chan func(), 1) // The buffer prevents blocking
go func() {
time.Sleep(2 * time.Second) // Stop after two seconds
vm.Interrupt <- func() {
panic(halt)
}
}()
vm.Run(unsafe) // Here be dragons (risky code)
vm.Interrupt = nil
}
Where is setTimeout/setInterval?
@ -242,6 +243,36 @@ Here is some more discussion of the issue:
var ErrVersion = errors.New("version mismatch")
```
#### type Error
```go
type Error struct {
}
```
An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc.
#### func (Error) Error
```go
func (err Error) Error() string
```
Error returns a description of the error
TypeError: 'def' is not a function
#### func (Error) String
```go
func (err Error) String() string
```
String returns a description of the error and a trace of where the error
occurred.
TypeError: 'def' is not a function
at xyz (<anonymous>:3:9)
at <anonymous>:7:1/
#### type FunctionCall
```go
@ -416,16 +447,16 @@ error if there was a problem during compilation.
#### func (*Otto) Copy
```go
func (self *Otto) Copy() *Otto
func (in *Otto) Copy() *Otto
```
Copy will create a copy/clone of the runtime.
Copy is useful for saving some processing time when creating many similar
runtimes.
Copy is useful for saving some time when creating many similar runtimes.
This implementation is alpha-ish, and works by introspecting every part of the
runtime and reallocating and then relinking everything back together. Please
report if you notice any inadvertent sharing of data between copies.
This method works by walking the original runtime and cloning each object,
scope, stash, etc. into a new runtime.
Be on the lookout for memory leaks or inadvertent sharing of resources.
#### func (Otto) Get
@ -562,12 +593,10 @@ NullValue will return a Value representing null.
func ToValue(value interface{}) (Value, error)
```
ToValue will convert an interface{} value to a value digestible by
otto/JavaScript This function will not work for advanced types (struct, map,
slice/array, etc.) and you probably should not use it.
otto/JavaScript
ToValue may be deprecated and removed in the near future.
Try Otto.ToValue for a replacement.
This function will not work for advanced types (struct, map, slice/array, etc.)
and you should use Otto.ToValue instead.
#### func TrueValue
@ -630,15 +659,13 @@ func (self Value) Export() (interface{}, error)
Export will attempt to convert the value to a Go representation and return it
via an interface{} kind.
WARNING: The interface function will be changing soon to:
Export returns an error, but it will always be nil. It is present for backwards
compatibility.
Export() interface{}
If a reasonable conversion is not possible, then the original value is returned.
If a reasonable conversion is not possible, then the original result is
returned.
undefined -> otto.Value (UndefinedValue())
null -> interface{}(nil)
undefined -> nil (FIXME?: Should be Value{})
null -> nil
boolean -> bool
number -> A number type (int, float32, uint64, ...)
string -> string

View file

@ -55,7 +55,7 @@ func Test_issue13(t *testing.T) {
t.Error(err)
t.FailNow()
}
is(result.toString(), "Xyzzy,42,def,ghi")
is(result.string(), "Xyzzy,42,def,ghi")
anything := struct {
Abc interface{}
@ -231,12 +231,12 @@ func Test_issue24(t *testing.T) {
}
{
vm.Set("abc", testStruct{Abc: true, Ghi: "Nothing happens."})
vm.Set("abc", _abcStruct{Abc: true, Ghi: "Nothing happens."})
value, err := vm.Get("abc")
is(err, nil)
export, _ := value.Export()
{
value, valid := export.(testStruct)
value, valid := export.(_abcStruct)
is(valid, true)
is(value.Abc, true)
@ -245,12 +245,12 @@ func Test_issue24(t *testing.T) {
}
{
vm.Set("abc", &testStruct{Abc: true, Ghi: "Nothing happens."})
vm.Set("abc", &_abcStruct{Abc: true, Ghi: "Nothing happens."})
value, err := vm.Get("abc")
is(err, nil)
export, _ := value.Export()
{
value, valid := export.(*testStruct)
value, valid := export.(*_abcStruct)
is(valid, true)
is(value.Abc, true)
@ -313,10 +313,22 @@ func Test_issue64(t *testing.T) {
})
}
func Test_issue73(t *testing.T) {
tt(t, func() {
test, vm := test()
vm.Set("abc", [4]int{3, 2, 1, 0})
test(`
var def = [ 0, 1, 2, 3 ];
JSON.stringify(def) + JSON.stringify(abc);
`, "[0,1,2,3][3,2,1,0]")
})
}
func Test_7_3_1(t *testing.T) {
tt(t, func() {
test(`
eval("var test7_3_1\u2028abc = 66;");
[ abc, typeof test7_3_1 ];
`, "66,undefined")
@ -430,13 +442,13 @@ def"
test(`
var abc = 0;
do {
if(typeof(def) === "function"){
abc = -1;
break;
} else {
abc = 1;
break;
}
if(typeof(def) === "function"){
abc = -1;
break;
} else {
abc = 1;
break;
}
} while(function def(){});
abc;
`, 1)
@ -502,3 +514,104 @@ def"
`, "1,0,\t abc def,\t abc ")
})
}
func Test_issue79(t *testing.T) {
tt(t, func() {
test, vm := test()
vm.Set("abc", []_abcStruct{
{
Ghi: "一",
Def: 1,
},
{
Def: 3,
Ghi: "三",
},
{
Def: 2,
Ghi: "二",
},
{
Def: 4,
Ghi: "四",
},
})
test(`
abc.sort(function(a,b){ return b.Def-a.Def });
def = [];
for (i = 0; i < abc.length; i++) {
def.push(abc[i].String())
}
def;
`, "四,三,二,一")
})
}
func Test_issue80(t *testing.T) {
tt(t, func() {
test, _ := test()
test(`
JSON.stringify([
1401868959,
14018689591,
140186895901,
1401868959001,
14018689590001,
140186895900001,
1401868959000001,
1401868959000001.5,
14018689590000001,
140186895900000001,
1401868959000000001,
14018689590000000001,
140186895900000000001,
140186895900000000001.5
]);
`, "[1401868959,14018689591,140186895901,1401868959001,14018689590001,140186895900001,1401868959000001,1.4018689590000015e+15,14018689590000001,140186895900000001,1401868959000000001,1.401868959e+19,1.401868959e+20,1.401868959e+20]")
})
}
func Test_issue87(t *testing.T) {
tt(t, func() {
test, vm := test()
test(`
var def = 0;
abc: {
for (;;) {
def = !1;
break abc;
}
def = !0;
}
def;
`, false)
_, err := vm.Run(`
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(h,s){var f={},g=f.lib={},q=function(){},m=g.Base={extend:function(a){q.prototype=this;var c=new q;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},
r=g.WordArray=m.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=s?c:4*a.length},toString:function(a){return(a||k).stringify(this)},concat:function(a){var c=this.words,d=a.words,b=this.sigBytes;a=a.sigBytes;this.clamp();if(b%4)for(var e=0;e<a;e++)c[b+e>>>2]|=(d[e>>>2]>>>24-8*(e%4)&255)<<24-8*((b+e)%4);else if(65535<d.length)for(e=0;e<a;e+=4)c[b+e>>>2]=d[e>>>2];else c.push.apply(c,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<
32-8*(c%4);a.length=h.ceil(c/4)},clone:function(){var a=m.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],d=0;d<a;d+=4)c.push(4294967296*h.random()|0);return new r.init(c,a)}}),l=f.enc={},k=l.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++){var e=c[b>>>2]>>>24-8*(b%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b+=2)d[b>>>3]|=parseInt(a.substr(b,
2),16)<<24-4*(b%8);return new r.init(d,c/2)}},n=l.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var d=[],b=0;b<a;b++)d.push(String.fromCharCode(c[b>>>2]>>>24-8*(b%4)&255));return d.join("")},parse:function(a){for(var c=a.length,d=[],b=0;b<c;b++)d[b>>>2]|=(a.charCodeAt(b)&255)<<24-8*(b%4);return new r.init(d,c)}},j=l.Utf8={stringify:function(a){try{return decodeURIComponent(escape(n.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return n.parse(unescape(encodeURIComponent(a)))}},
u=g.BufferedBlockAlgorithm=m.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,d=c.words,b=c.sigBytes,e=this.blockSize,f=b/(4*e),f=a?h.ceil(f):h.max((f|0)-this._minBufferSize,0);a=f*e;b=h.min(4*a,b);if(a){for(var g=0;g<a;g+=e)this._doProcessBlock(d,g);g=d.splice(0,a);c.sigBytes-=b}return new r.init(g,b)},clone:function(){var a=m.clone.call(this);
a._data=this._data.clone();return a},_minBufferSize:0});g.Hasher=u.extend({cfg:m.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){u.reset.call(this);this._doReset()},update:function(a){this._append(a);this._process();return this},finalize:function(a){a&&this._append(a);return this._doFinalize()},blockSize:16,_createHelper:function(a){return function(c,d){return(new a.init(d)).finalize(c)}},_createHmacHelper:function(a){return function(c,d){return(new t.HMAC.init(a,
d)).finalize(c)}}});var t=f.algo={};return f}(Math);
(function(h){for(var s=CryptoJS,f=s.lib,g=f.WordArray,q=f.Hasher,f=s.algo,m=[],r=[],l=function(a){return 4294967296*(a-(a|0))|0},k=2,n=0;64>n;){var j;a:{j=k;for(var u=h.sqrt(j),t=2;t<=u;t++)if(!(j%t)){j=!1;break a}j=!0}j&&(8>n&&(m[n]=l(h.pow(k,0.5))),r[n]=l(h.pow(k,1/3)),n++);k++}var a=[],f=f.SHA256=q.extend({_doReset:function(){this._hash=new g.init(m.slice(0))},_doProcessBlock:function(c,d){for(var b=this._hash.words,e=b[0],f=b[1],g=b[2],j=b[3],h=b[4],m=b[5],n=b[6],q=b[7],p=0;64>p;p++){if(16>p)a[p]=
c[d+p]|0;else{var k=a[p-15],l=a[p-2];a[p]=((k<<25|k>>>7)^(k<<14|k>>>18)^k>>>3)+a[p-7]+((l<<15|l>>>17)^(l<<13|l>>>19)^l>>>10)+a[p-16]}k=q+((h<<26|h>>>6)^(h<<21|h>>>11)^(h<<7|h>>>25))+(h&m^~h&n)+r[p]+a[p];l=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&f^e&g^f&g);q=n;n=m;m=h;h=j+k|0;j=g;g=f;f=e;e=k+l|0}b[0]=b[0]+e|0;b[1]=b[1]+f|0;b[2]=b[2]+g|0;b[3]=b[3]+j|0;b[4]=b[4]+h|0;b[5]=b[5]+m|0;b[6]=b[6]+n|0;b[7]=b[7]+q|0},_doFinalize:function(){var a=this._data,d=a.words,b=8*this._nDataBytes,e=8*a.sigBytes;
d[e>>>5]|=128<<24-e%32;d[(e+64>>>9<<4)+14]=h.floor(b/4294967296);d[(e+64>>>9<<4)+15]=b;a.sigBytes=4*d.length;this._process();return this._hash},clone:function(){var a=q.clone.call(this);a._hash=this._hash.clone();return a}});s.SHA256=q._createHelper(f);s.HmacSHA256=q._createHmacHelper(f)})(Math);
(function(){var h=CryptoJS,s=h.enc.Utf8;h.algo.HMAC=h.lib.Base.extend({init:function(f,g){f=this._hasher=new f.init;"string"==typeof g&&(g=s.parse(g));var h=f.blockSize,m=4*h;g.sigBytes>m&&(g=f.finalize(g));g.clamp();for(var r=this._oKey=g.clone(),l=this._iKey=g.clone(),k=r.words,n=l.words,j=0;j<h;j++)k[j]^=1549556828,n[j]^=909522486;r.sigBytes=l.sigBytes=m;this.reset()},reset:function(){var f=this._hasher;f.reset();f.update(this._iKey)},update:function(f){this._hasher.update(f);return this},finalize:function(f){var g=
this._hasher;f=g.finalize(f);g.reset();return g.finalize(this._oKey.clone().concat(f))}})})();
`)
is(err, nil)
test(`CryptoJS.HmacSHA256("Message", "secret");`, "aa747c502a898200f9e4fa21bac68136f886a0e27aec70ba06daf2e2a5cb5597")
})
}

View file

@ -2,7 +2,6 @@ package otto
import (
"encoding/hex"
"fmt"
"math"
"net/url"
"regexp"
@ -19,25 +18,26 @@ func builtinGlobal_eval(call FunctionCall) Value {
return src
}
runtime := call.runtime
program := runtime.cmpl_parseOrThrow(toString(src))
if call.evalHint {
runtime.EnterEvalExecutionContext(call)
defer runtime.LeaveExecutionContext()
program := runtime.cmpl_parseOrThrow(src.string())
if !call.eval {
// Not a direct call to eval, so we enter the global ExecutionContext
runtime.enterGlobalScope()
defer runtime.leaveScope()
}
returnValue := runtime.cmpl_evaluate_nodeProgram(program)
returnValue := runtime.cmpl_evaluate_nodeProgram(program, true)
if returnValue.isEmpty() {
return UndefinedValue()
return Value{}
}
return returnValue
}
func builtinGlobal_isNaN(call FunctionCall) Value {
value := toFloat(call.Argument(0))
value := call.Argument(0).float64()
return toValue_bool(math.IsNaN(value))
}
func builtinGlobal_isFinite(call FunctionCall) Value {
value := toFloat(call.Argument(0))
value := call.Argument(0).float64()
return toValue_bool(!math.IsNaN(value) && !math.IsInf(value, 0))
}
@ -70,7 +70,7 @@ func digitValue(chr rune) int {
}
func builtinGlobal_parseInt(call FunctionCall) Value {
input := strings.TrimSpace(toString(call.Argument(0)))
input := strings.TrimSpace(call.Argument(0).string())
if len(input) == 0 {
return NaNValue()
}
@ -153,7 +153,7 @@ var parseFloat_matchValid = regexp.MustCompile(`[0-9eE\+\-\.]|Infinity`)
func builtinGlobal_parseFloat(call FunctionCall) Value {
// Caveat emptor: This implementation does NOT match the specification
input := strings.TrimSpace(toString(call.Argument(0)))
input := strings.TrimSpace(call.Argument(0).string())
if parseFloat_matchBadSpecial.MatchString(input) {
return NaNValue()
}
@ -185,7 +185,7 @@ func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value {
case []uint16:
input = vl
default:
input = utf16.Encode([]rune(toString(value)))
input = utf16.Encode([]rune(value.string()))
}
if len(input) == 0 {
return toValue_string("")
@ -197,18 +197,17 @@ func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value {
value := input[index]
decode := utf16.Decode(input[index : index+1])
if value >= 0xDC00 && value <= 0xDFFF {
panic(newURIError("URI malformed"))
panic(call.runtime.panicURIError("URI malformed"))
}
if value >= 0xD800 && value <= 0xDBFF {
index += 1
if index >= length {
panic(newURIError("URI malformed"))
panic(call.runtime.panicURIError("URI malformed"))
}
// input = ..., value, value1, ...
value = value
value1 := input[index]
if value1 < 0xDC00 || value1 > 0xDFFF {
panic(newURIError("URI malformed"))
panic(call.runtime.panicURIError("URI malformed"))
}
decode = []rune{((rune(value) - 0xD800) * 0x400) + (rune(value1) - 0xDC00) + 0x10000}
}
@ -257,17 +256,17 @@ func _decodeURI(input string, reserve bool) (string, bool) {
}
func builtinGlobal_decodeURI(call FunctionCall) Value {
output, err := _decodeURI(toString(call.Argument(0)), true)
output, err := _decodeURI(call.Argument(0).string(), true)
if err {
panic(newURIError("URI malformed"))
panic(call.runtime.panicURIError("URI malformed"))
}
return toValue_string(output)
}
func builtinGlobal_decodeURIComponent(call FunctionCall) Value {
output, err := _decodeURI(toString(call.Argument(0)), false)
output, err := _decodeURI(call.Argument(0).string(), false)
if err {
panic(newURIError("URI malformed"))
panic(call.runtime.panicURIError("URI malformed"))
}
return toValue_string(output)
}
@ -346,48 +345,9 @@ func builtin_unescape(input string) string {
}
func builtinGlobal_escape(call FunctionCall) Value {
return toValue_string(builtin_escape(toString(call.Argument(0))))
return toValue_string(builtin_escape(call.Argument(0).string()))
}
func builtinGlobal_unescape(call FunctionCall) Value {
return toValue_string(builtin_unescape(toString(call.Argument(0))))
}
// Error
func builtinError(call FunctionCall) Value {
return toValue_object(call.runtime.newError("", call.Argument(0)))
}
func builtinNewError(self *_object, _ Value, argumentList []Value) Value {
return toValue_object(self.runtime.newError("", valueOfArrayIndex(argumentList, 0)))
}
func builtinError_toString(call FunctionCall) Value {
thisObject := call.thisObject()
if thisObject == nil {
panic(newTypeError())
}
name := "Error"
nameValue := thisObject.get("name")
if nameValue.IsDefined() {
name = toString(nameValue)
}
message := ""
messageValue := thisObject.get("message")
if messageValue.IsDefined() {
message = toString(messageValue)
}
if len(name) == 0 {
return toValue_string(message)
}
if len(message) == 0 {
return toValue_string(name)
}
return toValue_string(fmt.Sprintf("%s: %s", name, message))
return toValue_string(builtin_unescape(call.Argument(0).string()))
}

View file

@ -11,7 +11,7 @@ func builtinArray(call FunctionCall) Value {
return toValue_object(builtinNewArrayNative(call.runtime, call.ArgumentList))
}
func builtinNewArray(self *_object, _ Value, argumentList []Value) Value {
func builtinNewArray(self *_object, argumentList []Value) Value {
return toValue_object(builtinNewArrayNative(self.runtime, argumentList))
}
@ -19,7 +19,7 @@ func builtinNewArrayNative(runtime *_runtime, argumentList []Value) *_object {
if len(argumentList) == 1 {
firstArgument := argumentList[0]
if firstArgument.IsNumber() {
return runtime.newArray(arrayUint32(firstArgument))
return runtime.newArray(arrayUint32(runtime, firstArgument))
}
}
return runtime.newArrayOf(argumentList)
@ -30,7 +30,7 @@ func builtinArray_toString(call FunctionCall) Value {
join := thisObject.get("join")
if join.isCallable() {
join := join._object()
return join.Call(call.This, call.ArgumentList)
return join.call(call.This, call.ArgumentList, false, nativeFrame)
}
return builtinObject_toString(call)
}
@ -46,15 +46,15 @@ func builtinArray_toLocaleString(call FunctionCall) Value {
for index := int64(0); index < length; index += 1 {
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value._valueType {
switch value.kind {
case valueEmpty, valueUndefined, valueNull:
default:
object := call.runtime.toObject(value)
toLocaleString := object.get("toLocaleString")
if !toLocaleString.isCallable() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
stringValue = toLocaleString.call(toValue_object(object)).toString()
stringValue = toLocaleString.call(call.runtime, toValue_object(object)).string()
}
stringList = append(stringList, stringValue)
}
@ -66,11 +66,11 @@ func builtinArray_concat(call FunctionCall) Value {
valueArray := []Value{}
source := append([]Value{toValue_object(thisObject)}, call.ArgumentList...)
for _, item := range source {
switch item._valueType {
switch item.kind {
case valueObject:
object := item._object()
if isArray(object) {
length := toInteger(object.get("length")).value
length := object.get("length").number().int64
for index := int64(0); index < length; index += 1 {
name := strconv.FormatInt(index, 10)
if object.hasProperty(name) {
@ -94,7 +94,7 @@ func builtinArray_shift(call FunctionCall) Value {
length := int64(toUint32(thisObject.get("length")))
if 0 == length {
thisObject.put("length", toValue_int64(0), true)
return UndefinedValue()
return Value{}
}
first := thisObject.get("0")
for index := int64(1); index < length; index++ {
@ -130,7 +130,7 @@ func builtinArray_pop(call FunctionCall) Value {
length := int64(toUint32(thisObject.get("length")))
if 0 == length {
thisObject.put("length", toValue_uint32(0), true)
return UndefinedValue()
return Value{}
}
last := thisObject.get(arrayIndexToString(length - 1))
thisObject.delete(arrayIndexToString(length-1), true)
@ -143,7 +143,7 @@ func builtinArray_join(call FunctionCall) Value {
{
argument := call.Argument(0)
if argument.IsDefined() {
separator = toString(argument)
separator = argument.string()
}
}
thisObject := call.thisObject()
@ -155,10 +155,10 @@ func builtinArray_join(call FunctionCall) Value {
for index := int64(0); index < length; index += 1 {
value := thisObject.get(arrayIndexToString(index))
stringValue := ""
switch value._valueType {
switch value.kind {
case valueEmpty, valueUndefined, valueNull:
default:
stringValue = toString(value)
stringValue = value.string()
}
stringList = append(stringList, stringValue)
}
@ -370,8 +370,8 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int
}
if compare == nil {
j.value = toString(x)
k.value = toString(y)
j.value = x.string()
k.value = y.string()
if j.value == k.value {
return 0
@ -382,7 +382,7 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int
return 1
}
return int(toInt32(compare.Call(UndefinedValue(), []Value{x, y})))
return int(toInt32(compare.call(Value{}, []Value{x, y}, false, nativeFrame)))
}
func arraySortSwap(thisObject *_object, index0, index1 uint) {
@ -447,7 +447,7 @@ func builtinArray_sort(call FunctionCall) Value {
compare := compareValue._object()
if compareValue.IsUndefined() {
} else if !compareValue.isCallable() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
if length > 1 {
arraySortQuickSort(thisObject, 0, length-1, compare)
@ -464,7 +464,7 @@ func builtinArray_indexOf(call FunctionCall) Value {
if length := int64(toUint32(thisObject.get("length"))); length > 0 {
index := int64(0)
if len(call.ArgumentList) > 1 {
index = toInteger(call.Argument(1)).value
index = call.Argument(1).number().int64
}
if index < 0 {
if index += length; index < 0 {
@ -492,7 +492,7 @@ func builtinArray_lastIndexOf(call FunctionCall) Value {
length := int64(toUint32(thisObject.get("length")))
index := length - 1
if len(call.ArgumentList) > 1 {
index = toInteger(call.Argument(1)).value
index = call.Argument(1).number().int64
}
if 0 > index {
index += length
@ -523,15 +523,15 @@ func builtinArray_every(call FunctionCall) Value {
callThis := call.Argument(1)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).isTrue() {
if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() {
continue
}
return FalseValue()
return falseValue
}
}
return TrueValue()
return trueValue
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinArray_some(call FunctionCall) Value {
@ -542,14 +542,14 @@ func builtinArray_some(call FunctionCall) Value {
callThis := call.Argument(1)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).isTrue() {
return TrueValue()
if value := thisObject.get(key); iterator.call(call.runtime, callThis, value, toValue_int64(index), this).bool() {
return trueValue
}
}
}
return FalseValue()
return falseValue
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinArray_forEach(call FunctionCall) Value {
@ -560,12 +560,12 @@ func builtinArray_forEach(call FunctionCall) Value {
callThis := call.Argument(1)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
iterator.call(callThis, thisObject.get(key), toValue_int64(index), this)
iterator.call(call.runtime, callThis, thisObject.get(key), toValue_int64(index), this)
}
}
return UndefinedValue()
return Value{}
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinArray_map(call FunctionCall) Value {
@ -577,14 +577,14 @@ func builtinArray_map(call FunctionCall) Value {
values := make([]Value, length)
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
values[index] = iterator.call(callThis, thisObject.get(key), index, this)
values[index] = iterator.call(call.runtime, callThis, thisObject.get(key), index, this)
} else {
values[index] = UndefinedValue()
values[index] = Value{}
}
}
return toValue_object(call.runtime.newArrayOf(values))
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinArray_filter(call FunctionCall) Value {
@ -597,14 +597,14 @@ func builtinArray_filter(call FunctionCall) Value {
for index := int64(0); index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
value := thisObject.get(key)
if iterator.call(callThis, value, index, this).isTrue() {
if iterator.call(call.runtime, callThis, value, index, this).bool() {
values = append(values, value)
}
}
}
return toValue_object(call.runtime.newArrayOf(values))
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinArray_reduce(call FunctionCall) Value {
@ -630,13 +630,13 @@ func builtinArray_reduce(call FunctionCall) Value {
}
for ; index < length; index++ {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
accumulator = iterator.call(UndefinedValue(), accumulator, thisObject.get(key), key, this)
accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this)
}
}
return accumulator
}
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinArray_reduceRight(call FunctionCall) Value {
@ -662,11 +662,11 @@ func builtinArray_reduceRight(call FunctionCall) Value {
}
for ; index >= 0; index-- {
if key := arrayIndexToString(index); thisObject.hasProperty(key) {
accumulator = iterator.call(UndefinedValue(), accumulator, thisObject.get(key), key, this)
accumulator = iterator.call(call.runtime, Value{}, accumulator, thisObject.get(key), key, this)
}
}
return accumulator
}
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}

View file

@ -3,10 +3,10 @@ package otto
// Boolean
func builtinBoolean(call FunctionCall) Value {
return toValue_bool(toBoolean(call.Argument(0)))
return toValue_bool(call.Argument(0).bool())
}
func builtinNewBoolean(self *_object, _ Value, argumentList []Value) Value {
func builtinNewBoolean(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newBoolean(valueOfArrayIndex(argumentList, 0)))
}
@ -16,7 +16,7 @@ func builtinBoolean_toString(call FunctionCall) Value {
// Will throw a TypeError if ThisObject is not a Boolean
value = call.thisClassObject("Boolean").primitiveValue()
}
return toValue_string(toString(value))
return toValue_string(value.string())
}
func builtinBoolean_valueOf(call FunctionCall) Value {

View file

@ -21,12 +21,12 @@ func builtinDate(call FunctionCall) Value {
return toValue_string(date.Time().Format(builtinDate_goDateTimeLayout))
}
func builtinNewDate(self *_object, _ Value, argumentList []Value) Value {
func builtinNewDate(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newDate(newDateTime(argumentList, Time.Local)))
}
func builtinDate_toString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -34,7 +34,7 @@ func builtinDate_toString(call FunctionCall) Value {
}
func builtinDate_toDateString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -42,7 +42,7 @@ func builtinDate_toDateString(call FunctionCall) Value {
}
func builtinDate_toTimeString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -50,7 +50,7 @@ func builtinDate_toTimeString(call FunctionCall) Value {
}
func builtinDate_toUTCString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -58,7 +58,7 @@ func builtinDate_toUTCString(call FunctionCall) Value {
}
func builtinDate_toISOString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -69,20 +69,21 @@ func builtinDate_toJSON(call FunctionCall) Value {
object := call.thisObject()
value := object.DefaultValue(defaultValueHintNumber) // FIXME object.primitiveNumberValue
{ // FIXME value.isFinite
value := toFloat(value)
value := value.float64()
if math.IsNaN(value) || math.IsInf(value, 0) {
return NullValue()
return nullValue
}
}
toISOString := object.get("toISOString")
if !toISOString.isCallable() {
panic(newTypeError())
// FIXME
panic(call.runtime.panicTypeError())
}
return toISOString.call(toValue_object(object), []Value{})
return toISOString.call(call.runtime, toValue_object(object), []Value{})
}
func builtinDate_toGMTString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -90,7 +91,7 @@ func builtinDate_toGMTString(call FunctionCall) Value {
}
func builtinDate_getTime(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -101,15 +102,15 @@ func builtinDate_getTime(call FunctionCall) Value {
func builtinDate_setTime(call FunctionCall) Value {
object := call.thisObject()
date := dateObjectOf(object)
date.Set(toFloat(call.Argument(0)))
date := dateObjectOf(call.runtime, call.thisObject())
date.Set(call.Argument(0).float64())
object.value = date
return date.Value()
}
func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool) (*_object, *_dateObject, *_ecmaTime, []int) {
object := call.thisObject()
date := dateObjectOf(object)
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return nil, nil, nil, nil
}
@ -126,16 +127,14 @@ func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool
valueList := make([]int, argumentLimit)
for index := 0; index < argumentLimit; index++ {
value := call.ArgumentList[index]
if value.IsNaN() {
nm := value.number()
switch nm.kind {
case numberInteger, numberFloat:
default:
object.value = invalidDateObject
return nil, nil, nil, nil
}
integer := toInteger(value)
if !integer.valid() {
object.value = invalidDateObject
return nil, nil, nil, nil
}
valueList[index] = int(integer.value)
valueList[index] = int(nm.int64)
}
baseTime := date.Time()
if timeLocal {
@ -146,7 +145,7 @@ func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool
}
func builtinDate_parse(call FunctionCall) Value {
date := toString(call.Argument(0))
date := call.Argument(0).string()
return toValue_float64(dateParse(date))
}
@ -161,7 +160,7 @@ func builtinDate_now(call FunctionCall) Value {
// This is a placeholder
func builtinDate_toLocaleString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -170,7 +169,7 @@ func builtinDate_toLocaleString(call FunctionCall) Value {
// This is a placeholder
func builtinDate_toLocaleDateString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -179,7 +178,7 @@ func builtinDate_toLocaleDateString(call FunctionCall) Value {
// This is a placeholder
func builtinDate_toLocaleTimeString(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return toValue_string("Invalid Date")
}
@ -187,7 +186,7 @@ func builtinDate_toLocaleTimeString(call FunctionCall) Value {
}
func builtinDate_valueOf(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -197,7 +196,7 @@ func builtinDate_valueOf(call FunctionCall) Value {
func builtinDate_getYear(call FunctionCall) Value {
// Will throw a TypeError is ThisObject is nil or
// does not have Class of "Date"
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -207,7 +206,7 @@ func builtinDate_getYear(call FunctionCall) Value {
func builtinDate_getFullYear(call FunctionCall) Value {
// Will throw a TypeError is ThisObject is nil or
// does not have Class of "Date"
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -215,7 +214,7 @@ func builtinDate_getFullYear(call FunctionCall) Value {
}
func builtinDate_getUTCFullYear(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -223,7 +222,7 @@ func builtinDate_getUTCFullYear(call FunctionCall) Value {
}
func builtinDate_getMonth(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -231,7 +230,7 @@ func builtinDate_getMonth(call FunctionCall) Value {
}
func builtinDate_getUTCMonth(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -239,7 +238,7 @@ func builtinDate_getUTCMonth(call FunctionCall) Value {
}
func builtinDate_getDate(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -247,7 +246,7 @@ func builtinDate_getDate(call FunctionCall) Value {
}
func builtinDate_getUTCDate(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -256,7 +255,7 @@ func builtinDate_getUTCDate(call FunctionCall) Value {
func builtinDate_getDay(call FunctionCall) Value {
// Actually day of the week
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -264,7 +263,7 @@ func builtinDate_getDay(call FunctionCall) Value {
}
func builtinDate_getUTCDay(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -272,7 +271,7 @@ func builtinDate_getUTCDay(call FunctionCall) Value {
}
func builtinDate_getHours(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -280,7 +279,7 @@ func builtinDate_getHours(call FunctionCall) Value {
}
func builtinDate_getUTCHours(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -288,7 +287,7 @@ func builtinDate_getUTCHours(call FunctionCall) Value {
}
func builtinDate_getMinutes(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -296,7 +295,7 @@ func builtinDate_getMinutes(call FunctionCall) Value {
}
func builtinDate_getUTCMinutes(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -304,7 +303,7 @@ func builtinDate_getUTCMinutes(call FunctionCall) Value {
}
func builtinDate_getSeconds(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -312,7 +311,7 @@ func builtinDate_getSeconds(call FunctionCall) Value {
}
func builtinDate_getUTCSeconds(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -320,7 +319,7 @@ func builtinDate_getUTCSeconds(call FunctionCall) Value {
}
func builtinDate_getMilliseconds(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -328,7 +327,7 @@ func builtinDate_getMilliseconds(call FunctionCall) Value {
}
func builtinDate_getUTCMilliseconds(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}
@ -336,7 +335,7 @@ func builtinDate_getUTCMilliseconds(call FunctionCall) Value {
}
func builtinDate_getTimezoneOffset(call FunctionCall) Value {
date := dateObjectOf(call.thisObject())
date := dateObjectOf(call.runtime, call.thisObject())
if date.isNaN {
return NaNValue()
}

View file

@ -0,0 +1,126 @@
package otto
import (
"fmt"
)
func builtinError(call FunctionCall) Value {
return toValue_object(call.runtime.newError("", call.Argument(0)))
}
func builtinNewError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newError("", valueOfArrayIndex(argumentList, 0)))
}
func builtinError_toString(call FunctionCall) Value {
thisObject := call.thisObject()
if thisObject == nil {
panic(call.runtime.panicTypeError())
}
name := "Error"
nameValue := thisObject.get("name")
if nameValue.IsDefined() {
name = nameValue.string()
}
message := ""
messageValue := thisObject.get("message")
if messageValue.IsDefined() {
message = messageValue.string()
}
if len(name) == 0 {
return toValue_string(message)
}
if len(message) == 0 {
return toValue_string(name)
}
return toValue_string(fmt.Sprintf("%s: %s", name, message))
}
func (runtime *_runtime) newEvalError(message Value) *_object {
self := runtime.newErrorObject("EvalError", message)
self.prototype = runtime.global.EvalErrorPrototype
return self
}
func builtinEvalError(call FunctionCall) Value {
return toValue_object(call.runtime.newEvalError(call.Argument(0)))
}
func builtinNewEvalError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newEvalError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newTypeError(message Value) *_object {
self := runtime.newErrorObject("TypeError", message)
self.prototype = runtime.global.TypeErrorPrototype
return self
}
func builtinTypeError(call FunctionCall) Value {
return toValue_object(call.runtime.newTypeError(call.Argument(0)))
}
func builtinNewTypeError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newTypeError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newRangeError(message Value) *_object {
self := runtime.newErrorObject("RangeError", message)
self.prototype = runtime.global.RangeErrorPrototype
return self
}
func builtinRangeError(call FunctionCall) Value {
return toValue_object(call.runtime.newRangeError(call.Argument(0)))
}
func builtinNewRangeError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newRangeError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newURIError(message Value) *_object {
self := runtime.newErrorObject("URIError", message)
self.prototype = runtime.global.URIErrorPrototype
return self
}
func (runtime *_runtime) newReferenceError(message Value) *_object {
self := runtime.newErrorObject("ReferenceError", message)
self.prototype = runtime.global.ReferenceErrorPrototype
return self
}
func builtinReferenceError(call FunctionCall) Value {
return toValue_object(call.runtime.newReferenceError(call.Argument(0)))
}
func builtinNewReferenceError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newReferenceError(valueOfArrayIndex(argumentList, 0)))
}
func (runtime *_runtime) newSyntaxError(message Value) *_object {
self := runtime.newErrorObject("SyntaxError", message)
self.prototype = runtime.global.SyntaxErrorPrototype
return self
}
func builtinSyntaxError(call FunctionCall) Value {
return toValue_object(call.runtime.newSyntaxError(call.Argument(0)))
}
func builtinNewSyntaxError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newSyntaxError(valueOfArrayIndex(argumentList, 0)))
}
func builtinURIError(call FunctionCall) Value {
return toValue_object(call.runtime.newURIError(call.Argument(0)))
}
func builtinNewURIError(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newURIError(valueOfArrayIndex(argumentList, 0)))
}

View file

@ -1,6 +1,7 @@
package otto
import (
"fmt"
"regexp"
"strings"
"unicode"
@ -14,14 +15,14 @@ func builtinFunction(call FunctionCall) Value {
return toValue_object(builtinNewFunctionNative(call.runtime, call.ArgumentList))
}
func builtinNewFunction(self *_object, _ Value, argumentList []Value) Value {
func builtinNewFunction(self *_object, argumentList []Value) Value {
return toValue_object(builtinNewFunctionNative(self.runtime, argumentList))
}
func argumentList2parameterList(argumentList []Value) []string {
parameterList := make([]string, 0, len(argumentList))
for _, value := range argumentList {
tmp := strings.FieldsFunc(toString(value), func(chr rune) bool {
tmp := strings.FieldsFunc(value.string(), func(chr rune) bool {
return chr == ',' || unicode.IsSpace(chr)
})
parameterList = append(parameterList, tmp...)
@ -37,40 +38,51 @@ func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object
if count > 0 {
tmp := make([]string, 0, count-1)
for _, value := range argumentList[0 : count-1] {
tmp = append(tmp, toString(value))
tmp = append(tmp, value.string())
}
parameterList = strings.Join(tmp, ",")
body = toString(argumentList[count-1])
body = argumentList[count-1].string()
}
// FIXME
function, err := parser.ParseFunction(parameterList, body)
runtime.parseThrow(err) // Will panic/throw appropriately
cmpl_function := parseExpression(function)
cmpl := _compiler{}
cmpl_function := cmpl.parseExpression(function)
return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.GlobalEnvironment)
return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.globalStash)
}
func builtinFunction_toString(call FunctionCall) Value {
object := call.thisClassObject("Function") // Should throw a TypeError unless Function
return toValue_string(object.value.(_functionObject).source(object))
switch fn := object.value.(type) {
case _nativeFunctionObject:
return toValue_string(fmt.Sprintf("function %s() { [native code] }", fn.name))
case _nodeFunctionObject:
return toValue_string(fn.node.source)
case _bindFunctionObject:
return toValue_string("function () { [native code] }")
}
panic(call.runtime.panicTypeError("Function.toString()"))
}
func builtinFunction_apply(call FunctionCall) Value {
if !call.This.isCallable() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
this := call.Argument(0)
if this.IsUndefined() {
// FIXME Not ECMA5
this = toValue_object(call.runtime.GlobalObject)
this = toValue_object(call.runtime.globalObject)
}
argumentList := call.Argument(1)
switch argumentList._valueType {
switch argumentList.kind {
case valueUndefined, valueNull:
return call.thisObject().Call(this, []Value{})
return call.thisObject().call(this, nil, false, nativeFrame)
case valueObject:
default:
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
arrayObject := argumentList._object()
@ -80,29 +92,29 @@ func builtinFunction_apply(call FunctionCall) Value {
for index := int64(0); index < length; index++ {
valueArray[index] = arrayObject.get(arrayIndexToString(index))
}
return thisObject.Call(this, valueArray)
return thisObject.call(this, valueArray, false, nativeFrame)
}
func builtinFunction_call(call FunctionCall) Value {
if !call.This.isCallable() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
thisObject := call.thisObject()
this := call.Argument(0)
if this.IsUndefined() {
// FIXME Not ECMA5
this = toValue_object(call.runtime.GlobalObject)
this = toValue_object(call.runtime.globalObject)
}
if len(call.ArgumentList) >= 1 {
return thisObject.Call(this, call.ArgumentList[1:])
return thisObject.call(this, call.ArgumentList[1:], false, nativeFrame)
}
return thisObject.Call(this, []Value{})
return thisObject.call(this, nil, false, nativeFrame)
}
func builtinFunction_bind(call FunctionCall) Value {
target := call.This
if !target.isCallable() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
targetObject := target._object()
@ -110,7 +122,7 @@ func builtinFunction_bind(call FunctionCall) Value {
argumentList := call.slice(1)
if this.IsUndefined() {
// FIXME Do this elsewhere?
this = toValue_object(call.runtime.GlobalObject)
this = toValue_object(call.runtime.globalObject)
}
return toValue_object(call.runtime.newBoundFunction(targetObject, this, argumentList))

View file

@ -3,7 +3,7 @@ package otto
import (
"bytes"
"encoding/json"
"math"
"fmt"
"strings"
)
@ -23,13 +23,13 @@ func builtinJSON_parse(call FunctionCall) Value {
}
var root interface{}
err := json.Unmarshal([]byte(toString(call.Argument(0))), &root)
err := json.Unmarshal([]byte(call.Argument(0).string()), &root)
if err != nil {
panic(newSyntaxError(err.Error()))
panic(call.runtime.panicSyntaxError(err.Error()))
}
value, exists := builtinJSON_parseWalk(ctx, root)
if !exists {
value = UndefinedValue()
value = Value{}
}
if revive {
root := ctx.call.runtime.newObject()
@ -65,13 +65,13 @@ func builtinJSON_reviveWalk(ctx _builtinJSON_parseContext, holder *_object, name
})
}
}
return ctx.reviver.call(toValue_object(holder), name, value)
return ctx.reviver.call(ctx.call.runtime, toValue_object(holder), name, value)
}
func builtinJSON_parseWalk(ctx _builtinJSON_parseContext, rawValue interface{}) (Value, bool) {
switch value := rawValue.(type) {
case nil:
return NullValue(), true
return nullValue, true
case bool:
return toValue_bool(value), true
case string:
@ -120,7 +120,7 @@ func builtinJSON_stringify(call FunctionCall) Value {
length = 0
for index, _ := range propertyList {
value := replacer.get(arrayIndexToString(int64(index)))
switch value._valueType {
switch value.kind {
case valueObject:
switch value.value.(*_object).class {
case "String":
@ -133,7 +133,7 @@ func builtinJSON_stringify(call FunctionCall) Value {
default:
continue
}
name := toString(value)
name := value.string()
if seen[name] {
continue
}
@ -148,24 +148,24 @@ func builtinJSON_stringify(call FunctionCall) Value {
}
}
if spaceValue, exists := call.getArgument(2); exists {
if spaceValue._valueType == valueObject {
if spaceValue.kind == valueObject {
switch spaceValue.value.(*_object).class {
case "String":
spaceValue = toValue_string(toString(spaceValue))
spaceValue = toValue_string(spaceValue.string())
case "Number":
spaceValue = toNumber(spaceValue)
spaceValue = spaceValue.numberValue()
}
}
switch spaceValue._valueType {
switch spaceValue.kind {
case valueString:
value := toString(spaceValue)
value := spaceValue.string()
if len(value) > 10 {
ctx.gap = value[0:10]
} else {
ctx.gap = value
}
case valueNumber:
value := toInteger(spaceValue).value
value := spaceValue.number().int64
if value > 10 {
value = 10
} else if value < 0 {
@ -178,11 +178,11 @@ func builtinJSON_stringify(call FunctionCall) Value {
holder.put("", call.Argument(0), false)
value, exists := builtinJSON_stringifyWalk(ctx, "", holder)
if !exists {
return UndefinedValue()
return Value{}
}
valueJSON, err := json.Marshal(value)
if err != nil {
panic(newTypeError(err.Error()))
panic(call.runtime.panicTypeError(err.Error()))
}
if ctx.gap != "" {
valueJSON1 := bytes.Buffer{}
@ -198,7 +198,7 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho
if value.IsObject() {
object := value._object()
if toJSON := object.get("toJSON"); toJSON.IsFunction() {
value = toJSON.call(value, key)
value = toJSON.call(ctx.call.runtime, value, key)
} else {
// If the object is a GoStruct or something that implements json.Marshaler
if object.objectClass.marshalJSON != nil {
@ -211,31 +211,35 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho
}
if ctx.replacerFunction != nil {
value = (*ctx.replacerFunction).call(toValue_object(holder), key, value)
value = (*ctx.replacerFunction).call(ctx.call.runtime, toValue_object(holder), key, value)
}
if value._valueType == valueObject {
if value.kind == valueObject {
switch value.value.(*_object).class {
case "Boolean":
value = value._object().value.(Value)
case "String":
value = toValue_string(toString(value))
value = toValue_string(value.string())
case "Number":
value = toNumber(value)
value = value.numberValue()
}
}
switch value._valueType {
switch value.kind {
case valueBoolean:
return toBoolean(value), true
return value.bool(), true
case valueString:
return toString(value), true
return value.string(), true
case valueNumber:
value := toFloat(value)
if math.IsNaN(value) || math.IsInf(value, 0) {
integer := value.number()
switch integer.kind {
case numberInteger:
return integer.int64, true
case numberFloat:
return integer.float64, true
default:
return nil, true
}
return value, true
case valueNull:
return nil, true
case valueObject:
@ -243,14 +247,24 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho
if value := value._object(); nil != value {
for _, object := range ctx.stack {
if holder == object {
panic(newTypeError("Converting circular structure to JSON"))
panic(ctx.call.runtime.panicTypeError("Converting circular structure to JSON"))
}
}
ctx.stack = append(ctx.stack, value)
defer func() { ctx.stack = ctx.stack[:len(ctx.stack)-1] }()
}
if isArray(holder) {
length := holder.get("length").value.(uint32)
var length uint32
switch value := holder.get("length").value.(type) {
case uint32:
length = value
case int:
if value >= 0 {
length = uint32(value)
}
default:
panic(ctx.call.runtime.panicTypeError(fmt.Sprintf("JSON.stringify: invalid length: %v (%[1]T)", value)))
}
array := make([]interface{}, length)
for index, _ := range array {
name := arrayIndexToString(int64(index))

View file

@ -8,31 +8,31 @@ import (
// Math
func builtinMath_abs(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Abs(number))
}
func builtinMath_acos(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Acos(number))
}
func builtinMath_asin(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Asin(number))
}
func builtinMath_atan(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Atan(number))
}
func builtinMath_atan2(call FunctionCall) Value {
y := toFloat(call.Argument(0))
y := call.Argument(0).float64()
if math.IsNaN(y) {
return NaNValue()
}
x := toFloat(call.Argument(1))
x := call.Argument(1).float64()
if math.IsNaN(x) {
return NaNValue()
}
@ -40,27 +40,27 @@ func builtinMath_atan2(call FunctionCall) Value {
}
func builtinMath_cos(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Cos(number))
}
func builtinMath_ceil(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Ceil(number))
}
func builtinMath_exp(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Exp(number))
}
func builtinMath_floor(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Floor(number))
}
func builtinMath_log(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Log(number))
}
@ -69,14 +69,14 @@ func builtinMath_max(call FunctionCall) Value {
case 0:
return negativeInfinityValue()
case 1:
return toValue_float64(toFloat(call.ArgumentList[0]))
return toValue_float64(call.ArgumentList[0].float64())
}
result := toFloat(call.ArgumentList[0])
result := call.ArgumentList[0].float64()
if math.IsNaN(result) {
return NaNValue()
}
for _, value := range call.ArgumentList[1:] {
value := toFloat(value)
value := value.float64()
if math.IsNaN(value) {
return NaNValue()
}
@ -90,14 +90,14 @@ func builtinMath_min(call FunctionCall) Value {
case 0:
return positiveInfinityValue()
case 1:
return toValue_float64(toFloat(call.ArgumentList[0]))
return toValue_float64(call.ArgumentList[0].float64())
}
result := toFloat(call.ArgumentList[0])
result := call.ArgumentList[0].float64()
if math.IsNaN(result) {
return NaNValue()
}
for _, value := range call.ArgumentList[1:] {
value := toFloat(value)
value := value.float64()
if math.IsNaN(value) {
return NaNValue()
}
@ -108,8 +108,8 @@ func builtinMath_min(call FunctionCall) Value {
func builtinMath_pow(call FunctionCall) Value {
// TODO Make sure this works according to the specification (15.8.2.13)
x := toFloat(call.Argument(0))
y := toFloat(call.Argument(1))
x := call.Argument(0).float64()
y := call.Argument(1).float64()
if math.Abs(x) == 1 && math.IsInf(y, 0) {
return NaNValue()
}
@ -121,7 +121,7 @@ func builtinMath_random(call FunctionCall) Value {
}
func builtinMath_round(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
value := math.Floor(number + 0.5)
if value == 0 {
value = math.Copysign(0, number)
@ -130,16 +130,16 @@ func builtinMath_round(call FunctionCall) Value {
}
func builtinMath_sin(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Sin(number))
}
func builtinMath_sqrt(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Sqrt(number))
}
func builtinMath_tan(call FunctionCall) Value {
number := toFloat(call.Argument(0))
number := call.Argument(0).float64()
return toValue_float64(math.Tan(number))
}

View file

@ -9,7 +9,7 @@ import (
func numberValueFromNumberArgumentList(argumentList []Value) Value {
if len(argumentList) > 0 {
return toNumber(argumentList[0])
return argumentList[0].numberValue()
}
return toValue_int(0)
}
@ -18,7 +18,7 @@ func builtinNumber(call FunctionCall) Value {
return numberValueFromNumberArgumentList(call.ArgumentList)
}
func builtinNewNumber(self *_object, _ Value, argumentList []Value) Value {
func builtinNewNumber(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newNumber(numberValueFromNumberArgumentList(argumentList)))
}
@ -30,12 +30,12 @@ func builtinNumber_toString(call FunctionCall) Value {
if radixArgument.IsDefined() {
integer := toIntegerFloat(radixArgument)
if integer < 2 || integer > 36 {
panic(newRangeError("RangeError: toString() radix must be between 2 and 36"))
panic(call.runtime.panicRangeError("RangeError: toString() radix must be between 2 and 36"))
}
radix = int(integer)
}
if radix == 10 {
return toValue_string(toString(value))
return toValue_string(value.string())
}
return toValue_string(numberToStringRadix(value, radix))
}
@ -47,16 +47,16 @@ func builtinNumber_valueOf(call FunctionCall) Value {
func builtinNumber_toFixed(call FunctionCall) Value {
precision := toIntegerFloat(call.Argument(0))
if 20 < precision || 0 > precision {
panic(newRangeError("toFixed() precision must be between 0 and 20"))
panic(call.runtime.panicRangeError("toFixed() precision must be between 0 and 20"))
}
if call.This.IsNaN() {
return toValue_string("NaN")
}
value := toFloat(call.This)
value := call.This.float64()
if math.Abs(value) >= 1e21 {
return toValue_string(floatToString(value, 64))
}
return toValue_string(strconv.FormatFloat(toFloat(call.This), 'f', int(precision), 64))
return toValue_string(strconv.FormatFloat(call.This.float64(), 'f', int(precision), 64))
}
func builtinNumber_toExponential(call FunctionCall) Value {
@ -67,10 +67,10 @@ func builtinNumber_toExponential(call FunctionCall) Value {
if value := call.Argument(0); value.IsDefined() {
precision = toIntegerFloat(value)
if 0 > precision {
panic(newRangeError("RangeError: toExponential() precision must be greater than 0"))
panic(call.runtime.panicRangeError("RangeError: toString() radix must be between 2 and 36"))
}
}
return toValue_string(strconv.FormatFloat(toFloat(call.This), 'e', int(precision), 64))
return toValue_string(strconv.FormatFloat(call.This.float64(), 'e', int(precision), 64))
}
func builtinNumber_toPrecision(call FunctionCall) Value {
@ -79,13 +79,13 @@ func builtinNumber_toPrecision(call FunctionCall) Value {
}
value := call.Argument(0)
if value.IsUndefined() {
return toValue_string(toString(call.This))
return toValue_string(call.This.string())
}
precision := toIntegerFloat(value)
if 1 > precision {
panic(newRangeError("RangeError: toPrecision() precision must be greater than 1"))
panic(call.runtime.panicRangeError("RangeError: toPrecision() precision must be greater than 1"))
}
return toValue_string(strconv.FormatFloat(toFloat(call.This), 'g', int(precision), 64))
return toValue_string(strconv.FormatFloat(call.This.float64(), 'g', int(precision), 64))
}
func builtinNumber_toLocaleString(call FunctionCall) Value {

View file

@ -8,7 +8,7 @@ import (
func builtinObject(call FunctionCall) Value {
value := call.Argument(0)
switch value._valueType {
switch value.kind {
case valueUndefined, valueNull:
return toValue_object(call.runtime.newObject())
}
@ -16,9 +16,9 @@ func builtinObject(call FunctionCall) Value {
return toValue_object(call.runtime.toObject(value))
}
func builtinNewObject(self *_object, _ Value, argumentList []Value) Value {
func builtinNewObject(self *_object, argumentList []Value) Value {
value := valueOfArrayIndex(argumentList, 0)
switch value._valueType {
switch value.kind {
case valueNull, valueUndefined:
case valueNumber, valueString, valueBoolean:
return toValue_object(self.runtime.toObject(value))
@ -34,7 +34,7 @@ func builtinObject_valueOf(call FunctionCall) Value {
}
func builtinObject_hasOwnProperty(call FunctionCall) Value {
propertyName := toString(call.Argument(0))
propertyName := call.Argument(0).string()
thisObject := call.thisObject()
return toValue_bool(thisObject.hasOwnProperty(propertyName))
}
@ -42,27 +42,27 @@ func builtinObject_hasOwnProperty(call FunctionCall) Value {
func builtinObject_isPrototypeOf(call FunctionCall) Value {
value := call.Argument(0)
if !value.IsObject() {
return FalseValue()
return falseValue
}
prototype := call.toObject(value).prototype
thisObject := call.thisObject()
for prototype != nil {
if thisObject == prototype {
return TrueValue()
return trueValue
}
prototype = prototype.prototype
}
return FalseValue()
return falseValue
}
func builtinObject_propertyIsEnumerable(call FunctionCall) Value {
propertyName := toString(call.Argument(0))
propertyName := call.Argument(0).string()
thisObject := call.thisObject()
property := thisObject.getOwnProperty(propertyName)
if property != nil && property.enumerable() {
return TrueValue()
return trueValue
}
return FalseValue()
return falseValue
}
func builtinObject_toString(call FunctionCall) Value {
@ -80,20 +80,20 @@ func builtinObject_toString(call FunctionCall) Value {
func builtinObject_toLocaleString(call FunctionCall) Value {
toString := call.thisObject().get("toString")
if !toString.isCallable() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
return toString.call(call.This)
return toString.call(call.runtime, call.This)
}
func builtinObject_getPrototypeOf(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
if object.prototype == nil {
return NullValue()
return nullValue
}
return toValue_object(object.prototype)
@ -103,13 +103,13 @@ func builtinObject_getOwnPropertyDescriptor(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
name := toString(call.Argument(1))
name := call.Argument(1).string()
descriptor := object.getOwnProperty(name)
if descriptor == nil {
return UndefinedValue()
return Value{}
}
return toValue_object(call.runtime.fromPropertyDescriptor(*descriptor))
}
@ -118,10 +118,10 @@ func builtinObject_defineProperty(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
name := toString(call.Argument(1))
descriptor := toPropertyDescriptor(call.Argument(2))
name := call.Argument(1).string()
descriptor := toPropertyDescriptor(call.runtime, call.Argument(2))
object.defineOwnProperty(name, descriptor, true)
return objectValue
}
@ -130,12 +130,12 @@ func builtinObject_defineProperties(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
properties := call.runtime.toObject(call.Argument(1))
properties.enumerate(false, func(name string) bool {
descriptor := toPropertyDescriptor(properties.get(name))
descriptor := toPropertyDescriptor(call.runtime, properties.get(name))
object.defineOwnProperty(name, descriptor, true)
return true
})
@ -146,7 +146,7 @@ func builtinObject_defineProperties(call FunctionCall) Value {
func builtinObject_create(call FunctionCall) Value {
prototypeValue := call.Argument(0)
if !prototypeValue.IsNull() && !prototypeValue.IsObject() {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
object := call.runtime.newObject()
@ -156,7 +156,7 @@ func builtinObject_create(call FunctionCall) Value {
if propertiesValue.IsDefined() {
properties := call.runtime.toObject(propertiesValue)
properties.enumerate(false, func(name string) bool {
descriptor := toPropertyDescriptor(properties.get(name))
descriptor := toPropertyDescriptor(call.runtime, properties.get(name))
object.defineOwnProperty(name, descriptor, true)
return true
})
@ -170,7 +170,7 @@ func builtinObject_isExtensible(call FunctionCall) Value {
if object := object._object(); object != nil {
return toValue_bool(object.extensible)
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinObject_preventExtensions(call FunctionCall) Value {
@ -178,7 +178,7 @@ func builtinObject_preventExtensions(call FunctionCall) Value {
if object := object._object(); object != nil {
object.extensible = false
} else {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
return object
}
@ -199,7 +199,7 @@ func builtinObject_isSealed(call FunctionCall) Value {
})
return toValue_bool(result)
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinObject_seal(call FunctionCall) Value {
@ -214,7 +214,7 @@ func builtinObject_seal(call FunctionCall) Value {
})
object.extensible = false
} else {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
return object
}
@ -235,7 +235,7 @@ func builtinObject_isFrozen(call FunctionCall) Value {
})
return toValue_bool(result)
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinObject_freeze(call FunctionCall) Value {
@ -259,7 +259,7 @@ func builtinObject_freeze(call FunctionCall) Value {
})
object.extensible = false
} else {
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
return object
}
@ -272,7 +272,7 @@ func builtinObject_keys(call FunctionCall) Value {
})
return toValue_object(call.runtime.newArrayOf(keys))
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}
func builtinObject_getOwnPropertyNames(call FunctionCall) Value {
@ -285,5 +285,5 @@ func builtinObject_getOwnPropertyNames(call FunctionCall) Value {
})
return toValue_object(call.runtime.newArrayOf(propertyNames))
}
panic(newTypeError())
panic(call.runtime.panicTypeError())
}

View file

@ -17,7 +17,7 @@ func builtinRegExp(call FunctionCall) Value {
return toValue_object(call.runtime.newRegExp(pattern, flags))
}
func builtinNewRegExp(self *_object, _ Value, argumentList []Value) Value {
func builtinNewRegExp(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newRegExp(
valueOfArrayIndex(argumentList, 0),
valueOfArrayIndex(argumentList, 1),
@ -26,15 +26,15 @@ func builtinNewRegExp(self *_object, _ Value, argumentList []Value) Value {
func builtinRegExp_toString(call FunctionCall) Value {
thisObject := call.thisObject()
source := toString(thisObject.get("source"))
source := thisObject.get("source").string()
flags := []byte{}
if toBoolean(thisObject.get("global")) {
if thisObject.get("global").bool() {
flags = append(flags, 'g')
}
if toBoolean(thisObject.get("ignoreCase")) {
if thisObject.get("ignoreCase").bool() {
flags = append(flags, 'i')
}
if toBoolean(thisObject.get("multiline")) {
if thisObject.get("multiline").bool() {
flags = append(flags, 'm')
}
return toValue_string(fmt.Sprintf("/%s/%s", source, flags))
@ -42,17 +42,17 @@ func builtinRegExp_toString(call FunctionCall) Value {
func builtinRegExp_exec(call FunctionCall) Value {
thisObject := call.thisObject()
target := toString(call.Argument(0))
target := call.Argument(0).string()
match, result := execRegExp(thisObject, target)
if !match {
return NullValue()
return nullValue
}
return toValue_object(execResultToArray(call.runtime, target, result))
}
func builtinRegExp_test(call FunctionCall) Value {
thisObject := call.thisObject()
target := toString(call.Argument(0))
target := call.Argument(0).string()
match, _ := execRegExp(thisObject, target)
return toValue_bool(match)
}
@ -61,5 +61,5 @@ func builtinRegExp_compile(call FunctionCall) Value {
// This (useless) function is deprecated, but is here to provide some
// semblance of compatibility.
// Caveat emptor: it may not be around for long.
return UndefinedValue()
return Value{}
}

View file

@ -12,7 +12,7 @@ import (
func stringValueFromStringArgumentList(argumentList []Value) Value {
if len(argumentList) > 0 {
return toValue_string(toString(argumentList[0]))
return toValue_string(argumentList[0].string())
}
return toValue_string("")
}
@ -21,7 +21,7 @@ func builtinString(call FunctionCall) Value {
return stringValueFromStringArgumentList(call.ArgumentList)
}
func builtinNewString(self *_object, _ Value, argumentList []Value) Value {
func builtinNewString(self *_object, argumentList []Value) Value {
return toValue_object(self.runtime.newString(stringValueFromStringArgumentList(argumentList)))
}
@ -41,8 +41,8 @@ func builtinString_fromCharCode(call FunctionCall) Value {
}
func builtinString_charAt(call FunctionCall) Value {
checkObjectCoercible(call.This)
idx := int(toInteger(call.Argument(0)).value)
checkObjectCoercible(call.runtime, call.This)
idx := int(call.Argument(0).number().int64)
chr := stringAt(call.This._object().stringValue(), idx)
if chr == utf8.RuneError {
return toValue_string("")
@ -51,8 +51,8 @@ func builtinString_charAt(call FunctionCall) Value {
}
func builtinString_charCodeAt(call FunctionCall) Value {
checkObjectCoercible(call.This)
idx := int(toInteger(call.Argument(0)).value)
checkObjectCoercible(call.runtime, call.This)
idx := int(call.Argument(0).number().int64)
chr := stringAt(call.This._object().stringValue(), idx)
if chr == utf8.RuneError {
return NaNValue()
@ -61,19 +61,19 @@ func builtinString_charCodeAt(call FunctionCall) Value {
}
func builtinString_concat(call FunctionCall) Value {
checkObjectCoercible(call.This)
checkObjectCoercible(call.runtime, call.This)
var value bytes.Buffer
value.WriteString(toString(call.This))
value.WriteString(call.This.string())
for _, item := range call.ArgumentList {
value.WriteString(toString(item))
value.WriteString(item.string())
}
return toValue_string(value.String())
}
func builtinString_indexOf(call FunctionCall) Value {
checkObjectCoercible(call.This)
value := toString(call.This)
target := toString(call.Argument(0))
checkObjectCoercible(call.runtime, call.This)
value := call.This.string()
target := call.Argument(0).string()
if 2 > len(call.ArgumentList) {
return toValue_int(strings.Index(value, target))
}
@ -94,9 +94,9 @@ func builtinString_indexOf(call FunctionCall) Value {
}
func builtinString_lastIndexOf(call FunctionCall) Value {
checkObjectCoercible(call.This)
value := toString(call.This)
target := toString(call.Argument(0))
checkObjectCoercible(call.runtime, call.This)
value := call.This.string()
target := call.Argument(0).string()
if 2 > len(call.ArgumentList) || call.ArgumentList[1].IsUndefined() {
return toValue_int(strings.LastIndex(value, target))
}
@ -104,15 +104,15 @@ func builtinString_lastIndexOf(call FunctionCall) Value {
if length == 0 {
return toValue_int(strings.LastIndex(value, target))
}
start := toInteger(call.ArgumentList[1])
if !start.valid() {
start := call.ArgumentList[1].number()
if start.kind == numberInfinity { // FIXME
// startNumber is infinity, so start is the end of string (start = length)
return toValue_int(strings.LastIndex(value, target))
}
if 0 > start.value {
start.value = 0
if 0 > start.int64 {
start.int64 = 0
}
end := int(start.value) + len(target)
end := int(start.int64) + len(target)
if end > length {
end = length
}
@ -120,18 +120,18 @@ func builtinString_lastIndexOf(call FunctionCall) Value {
}
func builtinString_match(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := toString(call.This)
checkObjectCoercible(call.runtime, call.This)
target := call.This.string()
matcherValue := call.Argument(0)
matcher := matcherValue._object()
if !matcherValue.IsObject() || matcher.class != "RegExp" {
matcher = call.runtime.newRegExp(matcherValue, UndefinedValue())
matcher = call.runtime.newRegExp(matcherValue, Value{})
}
global := toBoolean(matcher.get("global"))
global := matcher.get("global").bool()
if !global {
match, result := execRegExp(matcher, target)
if !match {
return NullValue()
return nullValue
}
return toValue_object(execResultToArray(call.runtime, target, result))
}
@ -141,7 +141,7 @@ func builtinString_match(call FunctionCall) Value {
matchCount := len(result)
if result == nil {
matcher.put("lastIndex", toValue_int(0), true)
return UndefinedValue() // !match
return Value{} // !match
}
matchCount = len(result)
valueArray := make([]Value, matchCount)
@ -189,8 +189,8 @@ func builtinString_findAndReplaceString(input []byte, lastIndex int, match []int
}
func builtinString_replace(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := []byte(toString(call.This))
checkObjectCoercible(call.runtime, call.This)
target := []byte(call.This.string())
searchValue := call.Argument(0)
searchObject := searchValue._object()
@ -205,7 +205,7 @@ func builtinString_replace(call FunctionCall) Value {
find = -1
}
} else {
search = regexp.MustCompile(regexp.QuoteMeta(toString(searchValue)))
search = regexp.MustCompile(regexp.QuoteMeta(searchValue.string()))
}
found := search.FindAllSubmatchIndex(target, find)
@ -232,18 +232,18 @@ func builtinString_replace(call FunctionCall) Value {
if match[offset] != -1 {
argumentList[index] = toValue_string(target[match[offset]:match[offset+1]])
} else {
argumentList[index] = UndefinedValue()
argumentList[index] = Value{}
}
}
argumentList[matchCount+0] = toValue_int(match[0])
argumentList[matchCount+1] = toValue_string(target)
replacement := toString(replace.Call(UndefinedValue(), argumentList))
replacement := replace.call(Value{}, argumentList, false, nativeFrame).string()
result = append(result, []byte(replacement)...)
lastIndex = match[1]
}
} else {
replace := []byte(toString(replaceValue))
replace := []byte(replaceValue.string())
for _, match := range found {
result = builtinString_findAndReplaceString(result, lastIndex, match, target, replace)
lastIndex = match[1]
@ -260,17 +260,15 @@ func builtinString_replace(call FunctionCall) Value {
return toValue_string(string(result))
}
return UndefinedValue()
}
func builtinString_search(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := toString(call.This)
checkObjectCoercible(call.runtime, call.This)
target := call.This.string()
searchValue := call.Argument(0)
search := searchValue._object()
if !searchValue.IsObject() || search.class != "RegExp" {
search = call.runtime.newRegExp(searchValue, UndefinedValue())
search = call.runtime.newRegExp(searchValue, Value{})
}
result := search.regExpValue().regularExpression.FindStringIndex(target)
if result == nil {
@ -291,8 +289,8 @@ func stringSplitMatch(target string, targetLength int64, index uint, search stri
}
func builtinString_split(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := toString(call.This)
checkObjectCoercible(call.runtime, call.This)
target := call.This.string()
separatorValue := call.Argument(0)
limitValue := call.Argument(1)
@ -343,7 +341,7 @@ func builtinString_split(call FunctionCall) Value {
captureCount := len(match) / 2
for index := 1; index < captureCount; index++ {
offset := index * 2
value := UndefinedValue()
value := Value{}
if match[offset] != -1 {
value = toValue_string(target[match[offset]:match[offset+1]])
}
@ -367,7 +365,7 @@ func builtinString_split(call FunctionCall) Value {
return toValue_object(call.runtime.newArrayOf(valueArray))
} else {
separator := toString(separatorValue)
separator := separatorValue.string()
splitLimit := limit
excess := false
@ -389,13 +387,11 @@ func builtinString_split(call FunctionCall) Value {
return toValue_object(call.runtime.newArrayOf(valueArray))
}
return UndefinedValue()
}
func builtinString_slice(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := toString(call.This)
checkObjectCoercible(call.runtime, call.This)
target := call.This.string()
length := int64(len(target))
start, end := rangeStartEnd(call.ArgumentList, length, false)
@ -406,8 +402,8 @@ func builtinString_slice(call FunctionCall) Value {
}
func builtinString_substring(call FunctionCall) Value {
checkObjectCoercible(call.This)
target := toString(call.This)
checkObjectCoercible(call.runtime, call.This)
target := call.This.string()
length := int64(len(target))
start, end := rangeStartEnd(call.ArgumentList, length, true)
@ -418,7 +414,7 @@ func builtinString_substring(call FunctionCall) Value {
}
func builtinString_substr(call FunctionCall) Value {
target := toString(call.This)
target := call.This.string()
size := int64(len(target))
start, length := rangeStartLength(call.ArgumentList, size)
@ -443,42 +439,42 @@ func builtinString_substr(call FunctionCall) Value {
}
func builtinString_toLowerCase(call FunctionCall) Value {
checkObjectCoercible(call.This)
return toValue_string(strings.ToLower(toString(call.This)))
checkObjectCoercible(call.runtime, call.This)
return toValue_string(strings.ToLower(call.This.string()))
}
func builtinString_toUpperCase(call FunctionCall) Value {
checkObjectCoercible(call.This)
return toValue_string(strings.ToUpper(toString(call.This)))
checkObjectCoercible(call.runtime, call.This)
return toValue_string(strings.ToUpper(call.This.string()))
}
// 7.2 Table 2 — Whitespace Characters & 7.3 Table 3 - Line Terminator Characters
const builtinString_trim_whitespace = "\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF"
func builtinString_trim(call FunctionCall) Value {
checkObjectCoercible(call.This)
return toValue(strings.Trim(toString(call.This),
checkObjectCoercible(call.runtime, call.This)
return toValue(strings.Trim(call.This.string(),
builtinString_trim_whitespace))
}
// Mozilla extension, not ECMAScript 5
func builtinString_trimLeft(call FunctionCall) Value {
checkObjectCoercible(call.This)
return toValue(strings.TrimLeft(toString(call.This),
checkObjectCoercible(call.runtime, call.This)
return toValue(strings.TrimLeft(call.This.string(),
builtinString_trim_whitespace))
}
// Mozilla extension, not ECMAScript 5
func builtinString_trimRight(call FunctionCall) Value {
checkObjectCoercible(call.This)
return toValue(strings.TrimRight(toString(call.This),
checkObjectCoercible(call.runtime, call.This)
return toValue(strings.TrimRight(call.This.string(),
builtinString_trim_whitespace))
}
func builtinString_localeCompare(call FunctionCall) Value {
checkObjectCoercible(call.This)
this := toString(call.This)
that := toString(call.Argument(0))
checkObjectCoercible(call.runtime, call.This)
this := call.This.string()
that := call.Argument(0).string()
if this < that {
return toValue_int(-1)
} else if this == that {
@ -491,7 +487,7 @@ func builtinString_localeCompare(call FunctionCall) Value {
An alternate version of String.trim
func builtinString_trim(call FunctionCall) Value {
checkObjectCoercible(call.This)
return toValue_string(strings.TrimFunc(toString(call.This), isWhiteSpaceOrLineTerminator))
return toValue_string(strings.TrimFunc(call.string(.This), isWhiteSpaceOrLineTerminator))
}
*/

View file

@ -0,0 +1,155 @@
package otto
import (
"fmt"
)
type _clone struct {
runtime *_runtime
_object map[*_object]*_object
_objectStash map[*_objectStash]*_objectStash
_dclStash map[*_dclStash]*_dclStash
_fnStash map[*_fnStash]*_fnStash
}
func (in *_runtime) clone() *_runtime {
in.lck.Lock()
defer in.lck.Unlock()
out := &_runtime{}
clone := _clone{
runtime: out,
_object: make(map[*_object]*_object),
_objectStash: make(map[*_objectStash]*_objectStash),
_dclStash: make(map[*_dclStash]*_dclStash),
_fnStash: make(map[*_fnStash]*_fnStash),
}
globalObject := clone.object(in.globalObject)
out.globalStash = out.newObjectStash(globalObject, nil)
out.globalObject = globalObject
out.global = _global{
clone.object(in.global.Object),
clone.object(in.global.Function),
clone.object(in.global.Array),
clone.object(in.global.String),
clone.object(in.global.Boolean),
clone.object(in.global.Number),
clone.object(in.global.Math),
clone.object(in.global.Date),
clone.object(in.global.RegExp),
clone.object(in.global.Error),
clone.object(in.global.EvalError),
clone.object(in.global.TypeError),
clone.object(in.global.RangeError),
clone.object(in.global.ReferenceError),
clone.object(in.global.SyntaxError),
clone.object(in.global.URIError),
clone.object(in.global.JSON),
clone.object(in.global.ObjectPrototype),
clone.object(in.global.FunctionPrototype),
clone.object(in.global.ArrayPrototype),
clone.object(in.global.StringPrototype),
clone.object(in.global.BooleanPrototype),
clone.object(in.global.NumberPrototype),
clone.object(in.global.DatePrototype),
clone.object(in.global.RegExpPrototype),
clone.object(in.global.ErrorPrototype),
clone.object(in.global.EvalErrorPrototype),
clone.object(in.global.TypeErrorPrototype),
clone.object(in.global.RangeErrorPrototype),
clone.object(in.global.ReferenceErrorPrototype),
clone.object(in.global.SyntaxErrorPrototype),
clone.object(in.global.URIErrorPrototype),
}
out.eval = out.globalObject.property["eval"].value.(Value).value.(*_object)
out.globalObject.prototype = out.global.ObjectPrototype
// Not sure if this is necessary, but give some help to the GC
clone.runtime = nil
clone._object = nil
clone._objectStash = nil
clone._dclStash = nil
clone._fnStash = nil
return out
}
func (clone *_clone) object(in *_object) *_object {
if out, exists := clone._object[in]; exists {
return out
}
out := &_object{}
clone._object[in] = out
return in.objectClass.clone(in, out, clone)
}
func (clone *_clone) dclStash(in *_dclStash) (*_dclStash, bool) {
if out, exists := clone._dclStash[in]; exists {
return out, true
}
out := &_dclStash{}
clone._dclStash[in] = out
return out, false
}
func (clone *_clone) objectStash(in *_objectStash) (*_objectStash, bool) {
if out, exists := clone._objectStash[in]; exists {
return out, true
}
out := &_objectStash{}
clone._objectStash[in] = out
return out, false
}
func (clone *_clone) fnStash(in *_fnStash) (*_fnStash, bool) {
if out, exists := clone._fnStash[in]; exists {
return out, true
}
out := &_fnStash{}
clone._fnStash[in] = out
return out, false
}
func (clone *_clone) value(in Value) Value {
out := in
switch value := in.value.(type) {
case *_object:
out.value = clone.object(value)
}
return out
}
func (clone *_clone) valueArray(in []Value) []Value {
out := make([]Value, len(in))
for index, value := range in {
out[index] = clone.value(value)
}
return out
}
func (clone *_clone) stash(in _stash) _stash {
if in == nil {
return nil
}
return in.clone(clone)
}
func (clone *_clone) property(in _property) _property {
out := in
if value, valid := in.value.(Value); valid {
out.value = clone.value(value)
} else {
panic(fmt.Errorf("in.value.(Value) != true"))
}
return out
}
func (clone *_clone) dclProperty(in _dclProperty) _dclProperty {
out := in
out.value = clone.value(in.value)
return out
}

View file

@ -0,0 +1,24 @@
package otto
import (
"github.com/robertkrimen/otto/ast"
"github.com/robertkrimen/otto/file"
)
type _file struct {
name string
src string
base int // This will always be 1 or greater
}
type _compiler struct {
file *file.File
program *ast.Program
}
func (cmpl *_compiler) parse() *_nodeProgram {
if cmpl.program != nil {
cmpl.file = cmpl.program.File
}
return cmpl._parse(cmpl.program)
}

View file

@ -4,13 +4,20 @@ import (
"strconv"
)
func (self *_runtime) cmpl_evaluate_nodeProgram(node *_nodeProgram) Value {
func (self *_runtime) cmpl_evaluate_nodeProgram(node *_nodeProgram, eval bool) Value {
if !eval {
self.enterGlobalScope()
defer func() {
self.leaveScope()
}()
}
self.cmpl_functionDeclaration(node.functionList)
self.cmpl_variableDeclaration(node.varList)
self.scope.frame.file = node.file
return self.cmpl_evaluate_nodeStatementList(node.body)
}
func (self *_runtime) cmpl_call_nodeFunction(function *_object, environment *_functionEnvironment, node *_nodeFunctionLiteral, this Value, argumentList []Value) Value {
func (self *_runtime) cmpl_call_nodeFunction(function *_object, stash *_fnStash, node *_nodeFunctionLiteral, this Value, argumentList []Value) Value {
indexOfParameterName := make([]string, len(argumentList))
// function(abc, def, ghi)
@ -24,19 +31,21 @@ func (self *_runtime) cmpl_call_nodeFunction(function *_object, environment *_fu
if name == "arguments" {
argumentsFound = true
}
value := UndefinedValue()
value := Value{}
if index < len(argumentList) {
value = argumentList[index]
indexOfParameterName[index] = name
}
self.localSet(name, value)
// strict = false
self.scope.lexical.setValue(name, value, false)
}
if !argumentsFound {
arguments := self.newArgumentsObject(indexOfParameterName, environment, len(argumentList))
arguments := self.newArgumentsObject(indexOfParameterName, stash, len(argumentList))
arguments.defineProperty("callee", toValue_object(function), 0101, false)
environment.arguments = arguments
self.localSet("arguments", toValue_object(arguments))
stash.arguments = arguments
// strict = false
self.scope.lexical.setValue("arguments", toValue_object(arguments), false)
for index, _ := range argumentList {
if index < len(node.parameterList) {
continue
@ -50,38 +59,38 @@ func (self *_runtime) cmpl_call_nodeFunction(function *_object, environment *_fu
self.cmpl_variableDeclaration(node.varList)
result := self.cmpl_evaluate_nodeStatement(node.body)
if result.isResult() {
if result.kind == valueResult {
return result
}
return UndefinedValue()
return Value{}
}
func (self *_runtime) cmpl_functionDeclaration(list []*_nodeFunctionLiteral) {
executionContext := self._executionContext(0)
executionContext := self.scope
eval := executionContext.eval
environment := executionContext.VariableEnvironment
stash := executionContext.variable
for _, function := range list {
name := function.name
value := self.cmpl_evaluate_nodeExpression(function)
if !environment.HasBinding(name) {
environment.CreateMutableBinding(name, eval == true)
if !stash.hasBinding(name) {
stash.createBinding(name, eval == true, value)
} else {
// TODO 10.5.5.e
stash.setBinding(name, value, false) // TODO strict
}
// TODO 10.5.5.e
environment.SetMutableBinding(name, value, false) // TODO strict
}
}
func (self *_runtime) cmpl_variableDeclaration(list []string) {
executionContext := self._executionContext(0)
executionContext := self.scope
eval := executionContext.eval
environment := executionContext.VariableEnvironment
stash := executionContext.variable
for _, name := range list {
if !environment.HasBinding(name) {
environment.CreateMutableBinding(name, eval == true)
environment.SetMutableBinding(name, UndefinedValue(), false) // TODO strict
if !stash.hasBinding(name) {
stash.createBinding(name, eval == true, Value{}) // TODO strict?
}
}
}

View file

@ -13,10 +13,10 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value {
// If the Interrupt channel is nil, then
// we avoid runtime.Gosched() overhead (if any)
// FIXME: Test this
if self.Otto.Interrupt != nil {
if self.otto.Interrupt != nil {
runtime.Gosched()
select {
case value := <-self.Otto.Interrupt:
case value := <-self.otto.Interrupt:
value()
default:
}
@ -50,15 +50,14 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value {
return self.cmpl_evaluate_nodeDotExpression(node)
case *_nodeFunctionLiteral:
var local = self.LexicalEnvironment()
var local = self.scope.lexical
if node.name != "" {
local = self.newDeclarativeEnvironment(local)
local = self.newDeclarationStash(local)
}
value := toValue_object(self.newNodeFunction(node, local))
if node.name != "" {
local.CreateMutableBinding(node.name, false)
local.SetMutableBinding(node.name, value, false)
local.createBinding(node.name, false, value)
}
return value
@ -67,7 +66,7 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value {
// TODO Should be true or false (strictness) depending on context
// getIdentifierReference should not return nil, but we check anyway and panic
// so as not to propagate the nil into something else
reference := getIdentifierReference(self.LexicalEnvironment(), name, false)
reference := getIdentifierReference(self, self.scope.lexical, name, false, _at(node.idx))
if reference == nil {
// Should never get here!
panic(hereBeDragons("referenceError == nil: " + name))
@ -90,7 +89,7 @@ func (self *_runtime) cmpl_evaluate_nodeExpression(node _nodeExpression) Value {
return self.cmpl_evaluate_nodeSequenceExpression(node)
case *_nodeThisExpression:
return toValue_object(self._executionContext(0).this)
return toValue_object(self.scope.this)
case *_nodeUnaryExpression:
return self.cmpl_evaluate_nodeUnaryExpression(node)
@ -108,9 +107,9 @@ func (self *_runtime) cmpl_evaluate_nodeArrayLiteral(node *_nodeArrayLiteral) Va
for _, node := range node.value {
if node == nil {
valueArray = append(valueArray, Value{})
valueArray = append(valueArray, emptyValue)
} else {
valueArray = append(valueArray, self.GetValue(self.cmpl_evaluate_nodeExpression(node)))
valueArray = append(valueArray, self.cmpl_evaluate_nodeExpression(node).resolve())
}
}
@ -123,14 +122,14 @@ func (self *_runtime) cmpl_evaluate_nodeAssignExpression(node *_nodeAssignExpres
left := self.cmpl_evaluate_nodeExpression(node.left)
right := self.cmpl_evaluate_nodeExpression(node.right)
rightValue := self.GetValue(right)
rightValue := right.resolve()
result := rightValue
if node.operator != token.ASSIGN {
result = self.calculateBinaryExpression(node.operator, left, rightValue)
}
self.PutValue(left.reference(), result)
self.putValue(left.reference(), result)
return result
}
@ -138,22 +137,22 @@ func (self *_runtime) cmpl_evaluate_nodeAssignExpression(node *_nodeAssignExpres
func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpression) Value {
left := self.cmpl_evaluate_nodeExpression(node.left)
leftValue := self.GetValue(left)
leftValue := left.resolve()
switch node.operator {
// Logical
case token.LOGICAL_AND:
if !toBoolean(leftValue) {
if !leftValue.bool() {
return leftValue
}
right := self.cmpl_evaluate_nodeExpression(node.right)
return self.GetValue(right)
return right.resolve()
case token.LOGICAL_OR:
if toBoolean(leftValue) {
if leftValue.bool() {
return leftValue
}
right := self.cmpl_evaluate_nodeExpression(node.right)
return self.GetValue(right)
return right.resolve()
}
return self.calculateBinaryExpression(node.operator, leftValue, self.cmpl_evaluate_nodeExpression(node.right))
@ -161,57 +160,90 @@ func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpres
func (self *_runtime) cmpl_evaluate_nodeBinaryExpression_comparison(node *_nodeBinaryExpression) Value {
left := self.GetValue(self.cmpl_evaluate_nodeExpression(node.left))
right := self.GetValue(self.cmpl_evaluate_nodeExpression(node.right))
left := self.cmpl_evaluate_nodeExpression(node.left).resolve()
right := self.cmpl_evaluate_nodeExpression(node.right).resolve()
return toValue_bool(self.calculateComparison(node.operator, left, right))
}
func (self *_runtime) cmpl_evaluate_nodeBracketExpression(node *_nodeBracketExpression) Value {
target := self.cmpl_evaluate_nodeExpression(node.left)
targetValue := self.GetValue(target)
targetValue := target.resolve()
member := self.cmpl_evaluate_nodeExpression(node.member)
memberValue := self.GetValue(member)
memberValue := member.resolve()
// TODO Pass in base value as-is, and defer toObject till later?
return toValue(newPropertyReference(self.toObject(targetValue), toString(memberValue), false))
return toValue(newPropertyReference(self, self.toObject(targetValue), memberValue.string(), false, _at(node.idx)))
}
func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression, withArgumentList []interface{}) Value {
rt := self
this := Value{}
callee := self.cmpl_evaluate_nodeExpression(node.callee)
calleeValue := self.GetValue(callee)
argumentList := []Value{}
if withArgumentList != nil {
argumentList = self.toValueArray(withArgumentList...)
} else {
for _, argumentNode := range node.argumentList {
argumentList = append(argumentList, self.GetValue(self.cmpl_evaluate_nodeExpression(argumentNode)))
argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve())
}
}
this := UndefinedValue()
calleeReference := callee.reference()
evalHint := false
if calleeReference != nil {
if calleeReference.IsPropertyReference() {
calleeObject := calleeReference.GetBase().(*_object)
this = toValue_object(calleeObject)
} else {
// TODO ImplictThisValue
}
if calleeReference.GetName() == "eval" {
evalHint = true // Possible direct eval
rf := callee.reference()
vl := callee.resolve()
eval := false // Whether this call is a (candidate for) direct call to eval
name := ""
if rf != nil {
switch rf := rf.(type) {
case *_propertyReference:
name = rf.name
object := rf.base
this = toValue_object(object)
eval = rf.name == "eval" // Possible direct eval
case *_stashReference:
// TODO ImplicitThisValue
name = rf.name
eval = rf.name == "eval" // Possible direct eval
default:
// FIXME?
panic(rt.panicTypeError("Here be dragons"))
}
}
if !calleeValue.IsFunction() {
panic(newTypeError("%v is not a function", calleeValue))
at := _at(-1)
switch callee := node.callee.(type) {
case *_nodeIdentifier:
at = _at(callee.idx)
case *_nodeDotExpression:
at = _at(callee.idx)
case *_nodeBracketExpression:
at = _at(callee.idx)
}
return self.Call(calleeValue._object(), this, argumentList, evalHint)
frame := _frame{
callee: name,
file: self.scope.frame.file,
}
if !vl.IsFunction() {
if name == "" {
// FIXME Maybe typeof?
panic(rt.panicTypeError("%v is not a function", vl, at))
}
panic(rt.panicTypeError("'%s' is not a function", name, at))
}
self.scope.frame.offset = int(at)
return vl._object().call(this, argumentList, eval, frame)
}
func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditionalExpression) Value {
test := self.cmpl_evaluate_nodeExpression(node.test)
testValue := self.GetValue(test)
if toBoolean(testValue) {
testValue := test.resolve()
if testValue.bool() {
return self.cmpl_evaluate_nodeExpression(node.consequent)
}
return self.cmpl_evaluate_nodeExpression(node.alternate)
@ -219,27 +251,60 @@ func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditi
func (self *_runtime) cmpl_evaluate_nodeDotExpression(node *_nodeDotExpression) Value {
target := self.cmpl_evaluate_nodeExpression(node.left)
targetValue := self.GetValue(target)
targetValue := target.resolve()
// TODO Pass in base value as-is, and defer toObject till later?
object, err := self.objectCoerce(targetValue)
if err != nil {
panic(newTypeError(fmt.Sprintf("Cannot access member '%s' of %s", node.identifier, err.Error())))
panic(self.panicTypeError("Cannot access member '%s' of %s", node.identifier, err.Error()))
}
return toValue(newPropertyReference(object, node.identifier, false))
return toValue(newPropertyReference(self, object, node.identifier, false, _at(node.idx)))
}
func (self *_runtime) cmpl_evaluate_nodeNewExpression(node *_nodeNewExpression) Value {
rt := self
callee := self.cmpl_evaluate_nodeExpression(node.callee)
calleeValue := self.GetValue(callee)
argumentList := []Value{}
for _, argumentNode := range node.argumentList {
argumentList = append(argumentList, self.GetValue(self.cmpl_evaluate_nodeExpression(argumentNode)))
argumentList = append(argumentList, self.cmpl_evaluate_nodeExpression(argumentNode).resolve())
}
this := UndefinedValue()
if !calleeValue.IsFunction() {
panic(newTypeError("%v is not a function", calleeValue))
rf := callee.reference()
vl := callee.resolve()
name := ""
if rf != nil {
switch rf := rf.(type) {
case *_propertyReference:
name = rf.name
case *_stashReference:
name = rf.name
default:
panic(rt.panicTypeError("Here be dragons"))
}
}
return calleeValue._object().Construct(this, argumentList)
at := _at(-1)
switch callee := node.callee.(type) {
case *_nodeIdentifier:
at = _at(callee.idx)
case *_nodeDotExpression:
at = _at(callee.idx)
case *_nodeBracketExpression:
at = _at(callee.idx)
}
if !vl.IsFunction() {
if name == "" {
// FIXME Maybe typeof?
panic(rt.panicTypeError("%v is not a function", vl, at))
}
panic(rt.panicTypeError("'%s' is not a function", name, at))
}
self.scope.frame.offset = int(at)
return vl._object().construct(argumentList)
}
func (self *_runtime) cmpl_evaluate_nodeObjectLiteral(node *_nodeObjectLiteral) Value {
@ -249,15 +314,15 @@ func (self *_runtime) cmpl_evaluate_nodeObjectLiteral(node *_nodeObjectLiteral)
for _, property := range node.value {
switch property.kind {
case "value":
result.defineProperty(property.key, self.GetValue(self.cmpl_evaluate_nodeExpression(property.value)), 0111, false)
result.defineProperty(property.key, self.cmpl_evaluate_nodeExpression(property.value).resolve(), 0111, false)
case "get":
getter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.LexicalEnvironment())
getter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical)
descriptor := _property{}
descriptor.mode = 0211
descriptor.value = _propertyGetSet{getter, nil}
result.defineOwnProperty(property.key, descriptor, false)
case "set":
setter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.LexicalEnvironment())
setter := self.newNodeFunction(property.value.(*_nodeFunctionLiteral), self.scope.lexical)
descriptor := _property{}
descriptor.mode = 0211
descriptor.value = _propertyGetSet{nil, setter}
@ -274,7 +339,7 @@ func (self *_runtime) cmpl_evaluate_nodeSequenceExpression(node *_nodeSequenceEx
var result Value
for _, node := range node.sequence {
result = self.cmpl_evaluate_nodeExpression(node)
result = self.GetValue(result)
result = result.resolve()
}
return result
}
@ -284,31 +349,31 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi
target := self.cmpl_evaluate_nodeExpression(node.operand)
switch node.operator {
case token.TYPEOF, token.DELETE:
if target._valueType == valueReference && target.reference().IsUnresolvable() {
if target.kind == valueReference && target.reference().invalid() {
if node.operator == token.TYPEOF {
return toValue_string("undefined")
}
return TrueValue()
return trueValue
}
}
switch node.operator {
case token.NOT:
targetValue := self.GetValue(target)
if targetValue.toBoolean() {
return FalseValue()
targetValue := target.resolve()
if targetValue.bool() {
return falseValue
}
return TrueValue()
return trueValue
case token.BITWISE_NOT:
targetValue := self.GetValue(target)
targetValue := target.resolve()
integerValue := toInt32(targetValue)
return toValue_int32(^integerValue)
case token.PLUS:
targetValue := self.GetValue(target)
return toValue_float64(targetValue.toFloat())
targetValue := target.resolve()
return toValue_float64(targetValue.float64())
case token.MINUS:
targetValue := self.GetValue(target)
value := targetValue.toFloat()
targetValue := target.resolve()
value := targetValue.float64()
// TODO Test this
sign := float64(-1)
if math.Signbit(value) {
@ -316,45 +381,45 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi
}
return toValue_float64(math.Copysign(value, sign))
case token.INCREMENT:
targetValue := self.GetValue(target)
targetValue := target.resolve()
if node.postfix {
// Postfix++
oldValue := targetValue.toFloat()
oldValue := targetValue.float64()
newValue := toValue_float64(+1 + oldValue)
self.PutValue(target.reference(), newValue)
self.putValue(target.reference(), newValue)
return toValue_float64(oldValue)
} else {
// ++Prefix
newValue := toValue_float64(+1 + targetValue.toFloat())
self.PutValue(target.reference(), newValue)
newValue := toValue_float64(+1 + targetValue.float64())
self.putValue(target.reference(), newValue)
return newValue
}
case token.DECREMENT:
targetValue := self.GetValue(target)
targetValue := target.resolve()
if node.postfix {
// Postfix--
oldValue := targetValue.toFloat()
oldValue := targetValue.float64()
newValue := toValue_float64(-1 + oldValue)
self.PutValue(target.reference(), newValue)
self.putValue(target.reference(), newValue)
return toValue_float64(oldValue)
} else {
// --Prefix
newValue := toValue_float64(-1 + targetValue.toFloat())
self.PutValue(target.reference(), newValue)
newValue := toValue_float64(-1 + targetValue.float64())
self.putValue(target.reference(), newValue)
return newValue
}
case token.VOID:
self.GetValue(target) // FIXME Side effect?
return UndefinedValue()
target.resolve() // FIXME Side effect?
return Value{}
case token.DELETE:
reference := target.reference()
if reference == nil {
return TrueValue()
return trueValue
}
return toValue_bool(target.reference().Delete())
return toValue_bool(target.reference().delete())
case token.TYPEOF:
targetValue := self.GetValue(target)
switch targetValue._valueType {
targetValue := target.resolve()
switch targetValue.kind {
case valueUndefined:
return toValue_string("undefined")
case valueNull:
@ -366,7 +431,7 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi
case valueString:
return toValue_string("string")
case valueObject:
if targetValue._object().functionValue().call != nil {
if targetValue._object().isCall() {
return toValue_string("function")
}
return toValue_string("object")
@ -381,11 +446,11 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi
func (self *_runtime) cmpl_evaluate_nodeVariableExpression(node *_nodeVariableExpression) Value {
if node.initializer != nil {
// FIXME If reference is nil
left := getIdentifierReference(self.LexicalEnvironment(), node.name, false)
left := getIdentifierReference(self, self.scope.lexical, node.name, false, _at(node.idx))
right := self.cmpl_evaluate_nodeExpression(node.initializer)
rightValue := self.GetValue(right)
rightValue := right.resolve()
self.PutValue(left, rightValue)
self.putValue(left, rightValue)
}
return toValue_string(node.name)
}

View file

@ -12,10 +12,10 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value {
// If the Interrupt channel is nil, then
// we avoid runtime.Gosched() overhead (if any)
// FIXME: Test this
if self.Otto.Interrupt != nil {
if self.otto.Interrupt != nil {
runtime.Gosched()
select {
case value := <-self.Otto.Interrupt:
case value := <-self.otto.Interrupt:
value()
default:
}
@ -24,8 +24,18 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value {
switch node := node.(type) {
case *_nodeBlockStatement:
// FIXME If result is break, then return the empty value?
return self.cmpl_evaluate_nodeStatementList(node.list)
labels := self.labels
self.labels = nil
value := self.cmpl_evaluate_nodeStatementList(node.list)
switch value.kind {
case valueResult:
switch value.evaluateBreak(labels) {
case resultBreak:
return emptyValue
}
}
return value
case *_nodeBranchStatement:
target := node.label
@ -37,13 +47,13 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value {
}
case *_nodeDebuggerStatement:
return Value{} // Nothing happens.
return emptyValue // Nothing happens.
case *_nodeDoWhileStatement:
return self.cmpl_evaluate_nodeDoWhileStatement(node)
case *_nodeEmptyStatement:
return Value{}
return emptyValue
case *_nodeExpressionStatement:
return self.cmpl_evaluate_nodeExpression(node.expression)
@ -70,15 +80,15 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value {
case *_nodeReturnStatement:
if node.argument != nil {
return toValue(newReturnResult(self.GetValue(self.cmpl_evaluate_nodeExpression(node.argument))))
return toValue(newReturnResult(self.cmpl_evaluate_nodeExpression(node.argument).resolve()))
}
return toValue(newReturnResult(UndefinedValue()))
return toValue(newReturnResult(Value{}))
case *_nodeSwitchStatement:
return self.cmpl_evaluate_nodeSwitchStatement(node)
case *_nodeThrowStatement:
value := self.GetValue(self.cmpl_evaluate_nodeExpression(node.argument))
value := self.cmpl_evaluate_nodeExpression(node.argument).resolve()
panic(newException(value))
case *_nodeTryStatement:
@ -89,7 +99,7 @@ func (self *_runtime) cmpl_evaluate_nodeStatement(node _nodeStatement) Value {
for _, variable := range node.list {
self.cmpl_evaluate_nodeVariableExpression(variable.(*_nodeVariableExpression))
}
return Value{}
return emptyValue
case *_nodeWhileStatement:
return self.cmpl_evaluate_nodeWhileStatement(node)
@ -106,17 +116,17 @@ func (self *_runtime) cmpl_evaluate_nodeStatementList(list []_nodeStatement) Val
var result Value
for _, node := range list {
value := self.cmpl_evaluate_nodeStatement(node)
switch value._valueType {
switch value.kind {
case valueResult:
return value
case valueEmpty:
default:
// We have GetValue here to (for example) trigger a
// We have getValue here to (for example) trigger a
// ReferenceError (of the not defined variety)
// Not sure if this is the best way to error out early
// for such errors or if there is a better way
// TODO Do we still need this?
result = self.GetValue(value)
result = value.resolve()
}
}
return result
@ -129,12 +139,12 @@ func (self *_runtime) cmpl_evaluate_nodeDoWhileStatement(node *_nodeDoWhileState
test := node.test
result := Value{}
result := emptyValue
resultBreak:
for {
for _, node := range node.body {
value := self.cmpl_evaluate_nodeStatement(node)
switch value._valueType {
switch value.kind {
case valueResult:
switch value.evaluateBreakContinue(labels) {
case resultReturn:
@ -150,7 +160,7 @@ resultBreak:
}
}
resultContinue:
if !self.GetValue(self.cmpl_evaluate_nodeExpression(test)).isTrue() {
if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() {
// Stahp: do ... while (false)
break
}
@ -164,11 +174,11 @@ func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement
self.labels = nil
source := self.cmpl_evaluate_nodeExpression(node.source)
sourceValue := self.GetValue(source)
sourceValue := source.resolve()
switch sourceValue._valueType {
switch sourceValue.kind {
case valueUndefined, valueNull:
return emptyValue()
return emptyValue
}
sourceObject := self.toObject(sourceValue)
@ -176,22 +186,22 @@ func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement
into := node.into
body := node.body
result := Value{}
result := emptyValue
object := sourceObject
for object != nil {
enumerateValue := Value{}
enumerateValue := emptyValue
object.enumerate(false, func(name string) bool {
into := self.cmpl_evaluate_nodeExpression(into)
// In the case of: for (var abc in def) ...
if into.reference() == nil {
identifier := toString(into)
identifier := into.string()
// TODO Should be true or false (strictness) depending on context
into = toValue(getIdentifierReference(self.LexicalEnvironment(), identifier, false))
into = toValue(getIdentifierReference(self, self.scope.lexical, identifier, false, -1))
}
self.PutValue(into.reference(), toValue_string(name))
self.putValue(into.reference(), toValue_string(name))
for _, node := range body {
value := self.cmpl_evaluate_nodeStatement(node)
switch value._valueType {
switch value.kind {
case valueResult:
switch value.evaluateBreakContinue(labels) {
case resultReturn:
@ -233,22 +243,22 @@ func (self *_runtime) cmpl_evaluate_nodeForStatement(node *_nodeForStatement) Va
if initializer != nil {
initialResult := self.cmpl_evaluate_nodeExpression(initializer)
self.GetValue(initialResult) // Side-effect trigger
initialResult.resolve() // Side-effect trigger
}
result := Value{}
result := emptyValue
resultBreak:
for {
if test != nil {
testResult := self.cmpl_evaluate_nodeExpression(test)
testResultValue := self.GetValue(testResult)
if toBoolean(testResultValue) == false {
testResultValue := testResult.resolve()
if testResultValue.bool() == false {
break
}
}
for _, node := range body {
value := self.cmpl_evaluate_nodeStatement(node)
switch value._valueType {
switch value.kind {
case valueResult:
switch value.evaluateBreakContinue(labels) {
case resultReturn:
@ -266,7 +276,7 @@ resultBreak:
resultContinue:
if update != nil {
updateResult := self.cmpl_evaluate_nodeExpression(update)
self.GetValue(updateResult) // Side-effect trigger
updateResult.resolve() // Side-effect trigger
}
}
return result
@ -274,14 +284,14 @@ resultBreak:
func (self *_runtime) cmpl_evaluate_nodeIfStatement(node *_nodeIfStatement) Value {
test := self.cmpl_evaluate_nodeExpression(node.test)
testValue := self.GetValue(test)
if toBoolean(testValue) {
testValue := test.resolve()
if testValue.bool() {
return self.cmpl_evaluate_nodeStatement(node.consequent)
} else if node.alternate != nil {
return self.cmpl_evaluate_nodeStatement(node.alternate)
}
return Value{}
return emptyValue
}
func (self *_runtime) cmpl_evaluate_nodeSwitchStatement(node *_nodeSwitchStatement) Value {
@ -302,18 +312,18 @@ func (self *_runtime) cmpl_evaluate_nodeSwitchStatement(node *_nodeSwitchStateme
}
}
result := Value{}
result := emptyValue
if target != -1 {
for _, clause := range node.body[target:] {
for _, statement := range clause.consequent {
value := self.cmpl_evaluate_nodeStatement(statement)
switch value._valueType {
switch value.kind {
case valueResult:
switch value.evaluateBreak(labels) {
case resultReturn:
return value
case resultBreak:
return Value{}
return emptyValue
}
case valueEmpty:
default:
@ -332,14 +342,15 @@ func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Va
})
if exception && node.catch != nil {
lexicalEnvironment := self._executionContext(0).newDeclarativeEnvironment(self)
outer := self.scope.lexical
self.scope.lexical = self.newDeclarationStash(outer)
defer func() {
self._executionContext(0).LexicalEnvironment = lexicalEnvironment
self.scope.lexical = outer
}()
// TODO If necessary, convert TypeError<runtime> => TypeError
// That, is, such errors can be thrown despite not being JavaScript "native"
self.localSet(node.catch.parameter, tryCatchValue)
// strict = false
self.scope.lexical.setValue(node.catch.parameter, tryCatchValue, false)
// FIXME node.CatchParameter
// FIXME node.Catch
@ -350,7 +361,7 @@ func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Va
if node.finally != nil {
finallyValue := self.cmpl_evaluate_nodeStatement(node.finally)
if finallyValue.isResult() {
if finallyValue.kind == valueResult {
return finallyValue
}
}
@ -369,16 +380,16 @@ func (self *_runtime) cmpl_evaluate_nodeWhileStatement(node *_nodeWhileStatement
labels := append(self.labels, "")
self.labels = nil
result := Value{}
result := emptyValue
resultBreakContinue:
for {
if !self.GetValue(self.cmpl_evaluate_nodeExpression(test)).isTrue() {
if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() {
// Stahp: while (false) ...
break
}
for _, node := range body {
value := self.cmpl_evaluate_nodeStatement(node)
switch value._valueType {
switch value.kind {
case valueResult:
switch value.evaluateBreakContinue(labels) {
case resultReturn:
@ -399,11 +410,11 @@ resultBreakContinue:
func (self *_runtime) cmpl_evaluate_nodeWithStatement(node *_nodeWithStatement) Value {
object := self.cmpl_evaluate_nodeExpression(node.object)
objectValue := self.GetValue(object)
previousLexicalEnvironment, lexicalEnvironment := self._executionContext(0).newLexicalEnvironment(self.toObject(objectValue))
lexicalEnvironment.ProvideThis = true
outer := self.scope.lexical
lexical := self.newObjectStash(self.toObject(object.resolve()), outer)
self.scope.lexical = lexical
defer func() {
self._executionContext(0).LexicalEnvironment = previousLexicalEnvironment
self.scope.lexical = outer
}()
return self.cmpl_evaluate_nodeStatement(node.body)

Some files were not shown because too many files have changed in this diff Show more