Last active
December 22, 2015 14:09
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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("") | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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