<commit_before>// Copyright 2014-2015 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package src

import (
	"errors"
	"fmt"
	"io"
	"os"
	"reflect"
	"strings"
)

func Decode(r io.Reader) (*Project, error) {
	dec := newDecoder(r)
	return dec.decode()
}

func DecodeFile(path string) (*Project, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return Decode(f)
}

type decoder struct {
	scan *scanner
	buf  []byte
	err  error
	prj  *Project
}

func newDecoder(r io.Reader) *decoder {
	return &decoder{scan: newScanner(r), prj: &Project{}}
}

// TODO: implement
func (dec *decoder) decode() (*Project, error) {
	if _, tok, err := dec.scan.nextValue(); err != nil {
		return nil, dec.errorf(err)
	} else if tok != scanBeginObject {
		return nil, dec.errorf("expected '{' as first character")
	}

	if err := dec.decodeProject(); err != nil {
		return nil, dec.errorf(err)
	}

	if _, tok, err := dec.scan.nextValue(); err != nil {
		return nil, dec.errorf(err)
	} else if tok != scanEndObject {
		return nil, dec.errorf("expected '}' as last character")
	}

	return dec.prj, nil
}

func (dec *decoder) errorf(v interface{}) error {
	return fmt.Errorf("malformed json: %v", v)
}

func (dec *decoder) decodeProject() error {
	pv := reflect.ValueOf(dec.prj)

	for {
		key, err := dec.scan.nextKey()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		if key == "" {
			return errors.New("empty key")
		}

		val, tok, err := dec.scan.nextValue()
		if err != nil {
			return err
		}

		switch {
		case key == "packages":
			err = dec.decodePackages()
		case key == "languages":
			err = dec.decodeLanguages()
		case key == "repository":
			err = dec.decodeRepository()
		case tok == scanIntLit:
			var num int64
			num, err := dec.unmarshalInt(val)
			if err != nil {
				return err
			}
			f := pv.FieldByName(dec.tagToFieldName(key))
			f.SetInt(num)
		case tok == scanStringLit:
			var str string
			str, err := dec.unmarshalString(val)
			if err != nil {
				return err
			}
			f := pv.FieldByName(dec.tagToFieldName(key))
			f.SetString(str)
		default:
			return errors.New("unexpected value for project object")
		}

		if err != nil {
			return err
		}
	}
	return nil
}

func (dec *decoder) decodePackages() error {
	dec.prj.Packages = make([]*Package, 0)
	for {
		_, tok, err := dec.scan.nextValue()
		if err != nil {
			return err
		}
		if tok == scanEndArray {
			break
		}
		if tok != scanBeginObject {
			return errors.New("expected an object")
		}
		if err := dec.decodePackage(); err != nil {
			return err
		}
	}

	return nil
}

// TODO: implement
func (dec *decoder) decodePackage() error {
	for {

	}
	return nil
}

// TODO: implement
func (dec *decoder) decodeLanguages() error {
	return nil
}

// TODO: implement
func (dec *decoder) decodeLanguage() error {
	return nil
}

// TODO: implement
func (dec *decoder) decodeRepository() error {
	return nil
}

// TODO: implement
func (dec *decoder) unmarshalInt(data []byte) (int64, error) {
	return 0, nil
}

// TODO: implement
func (dec *decoder) unmarshalString(data []byte) (string, error) {
	return "", nil
}

// TODO: implement
func (dec *decoder) tagToFieldName(tag string) string {
	var field string
	for _, seg := range strings.Split(tag, "_") {
		if len(seg) == 0 {<commit_msg>src: start improving error handling<commit_after>// Copyright 2014-2015 The project AUTHORS. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package src

import (
	"errors"
	"fmt"
	"io"
	"os"
	"reflect"
	"strings"

	"github.com/DevMine/repotool/model"
)

func Decode(r io.Reader) (*Project, error) {
	dec := newDecoder(r)
	return dec.decode()
}

func DecodeFile(path string) (*Project, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return Decode(f)
}

type decoder struct {
	scan *scanner
	buf  []byte
	err  error
}

func newDecoder(r io.Reader) *decoder {
	return &decoder{scan: newScanner(r)}
}

// TODO: implement
func (dec *decoder) decode() (*Project, error) {
	if _, tok, err := dec.scan.nextValue(); err != nil {
		return nil, dec.errorf(err)
	} else if tok != scanBeginObject {
		return nil, dec.errorf("expected '{' as first character")
	}

	prj := dec.decodeProject()
	if dec.err != nil {
		return nil, dec.errorf(dec.err)
	}

	if _, tok, err := dec.scan.nextValue(); err != nil {
		return nil, dec.errorf(err)
	} else if tok != scanEndObject {
		return nil, dec.errorf("expected '}' as last character")
	}

	return prj, nil
}

func (dec *decoder) errorf(v interface{}) error {
	return fmt.Errorf("malformed json: %v", v)
}

func (dec *decoder) decodeProject() *Project {
	prj := &Project{}
	pv := reflect.ValueOf(prj)

	for {
		key, err := dec.scan.nextKey()
		if err != nil {
			if err == io.EOF {
				break
			}
			dec.err = err
			return nil
		}
		if key == "" {
			dec.err = errors.New("empty key")
			return nil
		}

		val, tok, err := dec.scan.nextValue()
		if err != nil {
			dec.err = err
			return nil
		}

		switch {
		case key == "packages":
			prj.Packages = dec.decodePackages()
		case key == "languages":
			prj.Langs = dec.decodeLanguages()
		case key == "repository":
			prj.Repo = dec.decodeRepository()
		case tok == scanIntLit:
			var num int64
			num, dec.err = dec.unmarshalInt(val)
			f := pv.FieldByName(dec.tagToFieldName(key))
			f.SetInt(num)
		case tok == scanStringLit:
			var str string
			str, dec.err = dec.unmarshalString(val)
			f := pv.FieldByName(dec.tagToFieldName(key))
			f.SetString(str)
		default:
			dec.err = errors.New("unexpected value for project object")
		}

		if dec.err != nil {
			return nil
		}
	}
	return prj
}

func (dec *decoder) decodePackages() []*Package {
	pkgs := make([]*Package, 0)
	for {
		if dec.err != nil {
			return nil
		}

		var tok int
		_, tok, dec.err = dec.scan.nextValue()
		if dec.err != nil {
			return nil
		}
		if tok == scanEndArray {
			break
		}
		if tok != scanBeginObject {
			dec.err = errors.New("expected an object")
		}
		pkgs = append(pkgs, dec.decodePackage())
	}

	return nil
}

// TODO: implement
func (dec *decoder) decodePackage() *Package {
	pkg := &Package{}
	pv := reflect.ValueOf(pkg)
	for {
		if dec.err != nil {
			return nil
		}

		var key string
		key, dec.err = dec.scan.nextKey()
		if dec.err != nil {
			return nil
		}

		val, tok, err := dec.scan.nextValue()
		if err != nil {
			dec.err = err
			return nil
		}

		switch {
		case key == "source_files":
			pkg.SrcFiles = dec.decodeSrcFiles()
		case key == "doc":
			pkg.Doc = dec.decodeStringsList()
		case tok == scanIntLit:
			var num int64
			num, dec.err = dec.unmarshalInt(val)
			f := pv.FieldByName(dec.tagToFieldName(key))
			f.SetInt(num)
		case tok == scanStringLit:
			var str string
			str, dec.err = dec.unmarshalString(val)
			if dec.err != nil {
				return nil
			}
			f := pv.FieldByName(dec.tagToFieldName(key))
			f.SetString(str)
		default:
			dec.err = errors.New("unexpected value for project object")
		}

		if dec.err != nil {
			return nil
		}
	}
	return pkg
}

// TODO: implement
func (dec *decoder) decodeSrcFiles() []*SrcFile {
	return nil
}

// TODO: implement
func (dec *decoder) decodeStringsList() []string {
	return nil
}

// TODO: implement
func (dec *decoder) decodeLanguages() []*Language {
	return nil
}

// TODO: implement
func (dec *decoder) decodeLanguage() *Language {
	return nil
}

// TODO: implement
func (dec *decoder) decodeRepository() *model.Repository {
	return nil
}

// TODO: implement
func (dec *decoder) unmarshalInt(data []byte) (int64, error) {
	return 0, nil
}

// TODO: implement
func (dec *decoder) unmarshalString(data []byte) (string, error) {
	return "", nil
}

// TODO: implement
func (dec *decoder) tagToFieldName(tag string) string {
	var field string
	for _, seg := range strings.Split(tag, "_") {
		if len(seg) == 0 {
{'fraction_non_alphanumeric': 0.14477480868147033, 'fraction_numerical': 0.00401455275373228, 'mean_word_length': 3.1979989468141126, 'pattern_counts': {'":': 8, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3773156', 'n_tokens_mistral': 3169, 'n_tokens_neox': 2839, 'n_words': 834}