Skip to content

Instantly share code, notes, and snippets.

@chrisdickinson
Last active December 22, 2015 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisdickinson/6484179 to your computer and use it in GitHub Desktop.
Save chrisdickinson/6484179 to your computer and use it in GitHub Desktop.
my first and second go programs. 1 TCP echo server, 1 JSON parser.
package main
import "math"
import "container/list"
import "strconv"
//import "fmt"
import "os"
import "encoding/json"
import "runtime/pprof"
type Node interface{}
func ToJSON(node Node) string {
out := ""
switch node.(type) {
case map[string]Node:
val := node.(map[string]Node)
out = "{"
first := 0
for key, val := range val {
if first != 0 {
out += ","
}
first = 1
out += "\"" + key + "\":" + ToJSON(val)
}
out += "}"
return out
case *list.List:
val := node.(*list.List)
out = "["
for el := val.Front(); el != nil; {
out += ToJSON(el.Value.(Node))
el = el.Next()
if el != nil {
out += ","
}
}
out += "]"
case string:
out = "\"" + node.(string) + "\""
case float64:
out = strconv.FormatFloat(node.(float64), 'f', -1, 64)
case nil:
out = "null"
case bool:
if node.(bool) {
out = "true"
} else {
out = "false"
}
}
return out
}
const (
E_UNEXPECTED = iota
E_INVALID_UNICODE
E_BAD_HEX
)
type JSONError struct {
kind int
at byte
}
func (err JSONError) Error() string {
switch err.kind {
case E_UNEXPECTED: return "unexpected"
}
return "unknown error"
}
type State func(byte) (State, error)
var (
TRUE = []byte{0x72, 0x75, 0x65}
FALSE = []byte{0x61, 0x6c, 0x73, 0x65}
NULL = []byte{0x75, 0x6c, 0x6c}
)
func JSONConstant(expected []byte, output Node, emit func(Node) (State, error)) (State, error) {
index := 0
length := len(expected)
var Constant State
Constant = func(input byte) (State, error) {
check := expected[index]
index += 1
if input != check {
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
if index < length {
return Constant, nil
}
return emit(output)
}
return Constant, nil
}
func JSONNumber(input byte, emit func(Node, byte) (State, error)) (State, error) {
sign := 1
number := 0
decimal := 0.0
esign := 1
exponent := 0
var (
Start State
Mid State
Number State
Decimal State
Later State
ESign State
Exponent State
Done State
)
if(input == 0x2d) {
sign = -1
return Start, nil
}
Start = func(input byte) (State, error) {
if input == 0x30 {
return Mid, nil
}
if input > 0x30 && input < 0x40 {
return Number(input)
}
err := JSONError {E_UNEXPECTED, input}
return nil, err
}
Mid = func(input byte) (State, error) {
if (input == 0x2e) {
return Decimal, nil
}
return Later(input)
}
Number = func(input byte) (State, error) {
if input >= 0x30 && input < 0x40 {
number = number * 10 + (int(input) - 0x30)
return Number, nil
}
return Mid(input)
}
Decimal = func(input byte) (State, error) {
if input >= 0x30 && input < 0x40 {
decimal = (decimal + float64(int(input) - 0x30)) / 10.0
return Decimal, nil
}
return Later(input)
}
Later = func(input byte) (State, error) {
if input == 0x45 || input == 0x65 {
return ESign, nil
}
return Done(input)
}
ESign = func(input byte) (State, error) {
if input == 0x2b {
return Exponent, nil
}
if input == 0x2d {
esign = -1
return Exponent, nil
}
return Exponent(input)
}
Exponent = func(input byte) (State, error) {
if input >= 0x30 && input < 0x40 {
exponent = exponent * 10 + (int(input) - 0x30)
return Exponent, nil
}
return Done(input)
}
Done = func(input byte) (State, error) {
value := float64(sign) * (float64(number) + decimal)
if exponent != 0 {
value *= math.Pow(10, float64(esign * exponent))
}
return emit(value, input)
}
return Start(input)
}
func JSONUtf8(input byte, emit func(int) (State, error)) (State, error) {
num := int(0)
left := int(0)
var Utf8 State
if input >= 0xc0 && input < 0xe0 {
left = 1
num = int(input & 0x1f) << 6
}
if input >= 0xe0 && input < 0xf0 {
left = 2
num = int(input & 0xf) << 12
}
if input > 0xf0 && input < 0xf8 {
left = 3
num = int(input & 0x07) << 18
}
if(left == 0 && num == 0) {
err := JSONError{E_INVALID_UNICODE, input}
return nil, err
}
Utf8 = func(input byte) (State, error) {
if(input & 0xc0 != 0x80) {
err := JSONError{E_INVALID_UNICODE, input}
return nil, err
}
left -= 1
num |= int(input & byte(0x3f)) << (uint(left) * 6)
if left != 0 {
return Utf8, nil
}
return emit(num)
}
return Utf8, nil
}
func JSONHexMachine(emit func(int) (State, error)) (State, error) {
left := 4
num := 0
var Hex State
Hex = func(input byte) (State, error) {
idx := byte(0)
if input >= 0x30 && input < 0x40 {
idx = input - byte(0x30)
} else if input >= 0x61 && input < 0x66 {
idx = input - byte(0x57)
} else if input >= 0x41 && input < 0x46 {
idx = input - byte(0x30)
} else {
err := JSONError{E_BAD_HEX, input}
return nil, err
}
left -= 1
num |= int(idx) << uint(left * 4)
if left != 0 {
return Hex, nil
}
return emit(num)
}
return Hex, nil
}
func JSONString(emit func(Node) (State, error)) (State, error) {
str := ""
var (
String State
EscapedString State
)
_OnCharCode := func(codepoint int) (State, error) {
out, err := strconv.Unquote(strconv.QuoteRune(rune(codepoint)))
if err != nil {
return nil, err
}
str += out
return String, nil
}
String = func(input byte) (State, error) {
if input == 0x22 {
return emit(str)
}
if input == 0x5c {
return EscapedString, nil
}
if (input & 0x80) != 0 {
return JSONUtf8(input, _OnCharCode)
}
if input < 0x20 {
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
bytarr := [1]byte{input}
str += string(bytarr[0:])
return String, nil
}
EscapedString = func(input byte) (State, error) {
if input == 0x22 || input == 0x5c || input == 0x2f {
bytarr := [1]byte{input}
str += string(bytarr[0:])
return String, nil
}
switch input {
case 0x62: str += "\b"
case 0x66: str += "\f"
case 0x6e: str += "\n"
case 0x72: str += "\r"
case 0x74: str += "\t"
case 0x75: return JSONHexMachine(_OnCharCode)
}
return String, nil
}
return String, nil
}
func JSONObject(emit func(Node) (State, error)) (State, error) {
obj := make(map[string]Node)
var key string
var (
Object State
Key State
Colon State
Comma State
)
_OnValue := func(value Node) {
obj[key] = value
}
_OnKey := func(value Node) (State, error) {
key = value.(string)
return Colon, nil
}
Object = func(input byte) (State, error) {
if input == 0x7d {
return emit(obj)
}
return Key(input)
}
Key = func(input byte) (State, error) {
if input == 0x09 || input == 0x0a || input == 0x0d || input == 0x20 {
return Key, nil
}
if input == 0x22 {
return JSONString(_OnKey)
}
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
Colon = func(input byte) (State, error) {
if input == 0x09 || input == 0x0a || input == 0x0d || input == 0x20 {
return Key, nil
}
if input == 0x3a {
return JSONMachine(_OnValue, Comma), nil
}
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
Comma = func(input byte) (State, error) {
if input == 0x09 || input == 0x0a || input == 0x0d || input == 0x20 {
return Comma, nil
}
if input == 0x2c {
return Key, nil
}
if input == 0x7d {
return emit(obj)
}
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
return Object, nil
}
func JSONArray(emit func(Node) (State, error)) (State, error) {
array := list.New()
var (
Array State
Comma State
)
_OnValue := func(value Node) {
array.PushBack(value)
}
Array = func(input byte) (State, error) {
if input == 0x5d {
return emit(array)
}
return JSONMachine(_OnValue, Comma)(input)
}
Comma = func(input byte) (State, error) {
switch input {
case 0x09, 0x0a, 0x0d, 0x20:
return Comma, nil
case 0x2c:
return JSONMachine(_OnValue, Comma), nil
case 0x5d:
return emit(array)
}
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
return Array, nil
}
func JSONMachine(emit func(Node), next State) State {
var JSONValue State
_OnValue := func(value Node) (State, error) {
emit(value)
return next, nil
}
_OnNumber := func(number Node, last byte) (State, error) {
emit(number)
return JSONValue(last)
}
JSONValue = func(input byte) (State, error) {
if input == 0x2d || (input >= 0x30 && input < 0x40) {
return JSONNumber(input, _OnNumber)
}
switch input {
case 0x09, 0x0a, 0x0d, 0x20:
return JSONValue, nil
case 0x22:
return JSONString(_OnValue)
case 0x7b:
return JSONObject(_OnValue)
case 0x5b:
return JSONArray(_OnValue)
case 0x74:
return JSONConstant(TRUE, true, _OnValue)
case 0x66:
return JSONConstant(FALSE, false, _OnValue)
case 0x6e:
return JSONConstant(NULL, nil, _OnValue)
}
if &next == &JSONValue {
err := JSONError{E_UNEXPECTED, input}
return nil, err
}
return next(input)
}
if next == nil {
next = JSONValue
}
return JSONValue
}
func oldmain() {
var value interface {}
decoder := json.NewDecoder(os.Stdin)
err := decoder.Decode(&value)
if err != nil {
return
}
}
func main() {
const LENGTH = 1024 * 1024
var bytes [LENGTH]byte
var node Node
f, err := os.Create("out.prof")
if err != nil {
return
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
ondata := func(in Node) {
//fmt.Println("got node", ToJSON(in))
node = in
}
state := JSONMachine(ondata, nil)
for {
read, err := os.Stdin.Read(bytes[0:])
if err != nil {
break
}
for i := 0; i < read; i++ {
state, err = state(bytes[i])
}
}
//fmt.Println("")
}
package main
import "net"
import "bytes"
import "strings"
func handle(conn net.Conn) int {
var in [8192]byte
buf := bytes.NewBuffer(in[0:])
for {
val, err := conn.Read(in[0:])
str := strings.ToUpper(buf.String())
buf.WriteString(str)
conn.Write(buf.Bytes())
if err != nil || val == 0 {
break
}
}
return 0
}
func main() {
line, err := net.Listen("tcp", ":8080")
if err != nil {
return
}
for {
conn, err := line.Accept()
if err != nil {
continue
}
go handle(conn)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment