wsfmt/wsfmt.go
2018-05-03 13:51:49 -07:00

555 lines
12 KiB
Go

package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
"timmy.narnian.us/git/timmy/wsfmt/text/lex"
)
type stateFn func(*Formatter) stateFn
type FmtSettings struct{}
type Formatter struct {
l *lex.Lexer
pToken lex.Item
token lex.Item
nToken lex.Item
state stateFn
maxNewlines int
newlineCount int
scopeLevel []int
tempScopeLevel int
eol, CASE bool
parenDepth int
}
var (
blank = lex.Item{Pos: -1}
b []byte
err error
)
func main() {
file, _ := os.Open(os.Args[1])
f := Format(nil, file)
f.run()
}
func Format(typ *FmtSettings, text io.Reader) (f *Formatter) {
FILE := transform.NewReader(text, unicode.BOMOverride(unicode.UTF8.NewDecoder().Transformer))
b, err = ioutil.ReadAll(FILE)
if err != nil {
panic(err)
}
f = &Formatter{}
f.l = lex.Lex("name", string(b))
f.maxNewlines = 3
f.nToken = blank
return f
}
func (f *Formatter) next() lex.Item {
f.pToken = f.token
var temp lex.Item
if f.nToken == blank {
temp = f.l.NextItem()
} else {
temp = f.nToken
f.nToken = blank
}
for ; temp.Typ == lex.ItemSpace || temp.Typ == lex.ItemNewline; temp = f.l.NextItem() {
}
f.token = temp
return f.token
}
func (f *Formatter) peek() lex.Item {
if f.nToken == blank {
temp := f.l.NextItem()
count := 0
for ; temp.Typ == lex.ItemSpace || temp.Typ == lex.ItemNewline; temp = f.l.NextItem() {
if temp.Typ == lex.ItemNewline {
count += strings.Count(temp.Val, "\n")
}
}
if count < 3 {
f.newlineCount = count
} else {
f.newlineCount = 3
}
f.nToken = temp
}
return f.nToken
}
func (f *Formatter) run() {
for f.state = format; f.state != nil; {
f.state = f.state(f)
}
}
func format(f *Formatter) stateFn {
switch t := f.next().Typ; {
case t == lex.ItemEOF:
return nil
case t == lex.ItemError:
fmt.Print("error:", f.token.Val)
return nil
case t == lex.ItemComment:
f.printComment()
case t == lex.ItemFunction:
return formatFunction
case t == lex.ItemIf, t == lex.ItemWhile, t == lex.ItemFor, t == lex.ItemSwitch:
return formatConditional
case t == lex.ItemElse:
if f.pToken.Typ == lex.ItemRightBrace {
fmt.Printf(" else")
} else {
fmt.Print("else")
}
if f.peek().Typ != lex.ItemLeftBrace && f.peek().Typ != lex.ItemIf {
f.scopeLevel[len(f.scopeLevel)-1]++
printNewline(f)
printTab(f)
}
case t == lex.ItemReturn:
fmt.Printf("%s ", f.token.Val)
case t == lex.ItemModifiers, t == lex.ItemIdentifier, t == lex.ItemNumber, t == lex.ItemBool, t == lex.ItemString:
printIdentifier(f)
case isChar(t):
return printChar(f)
case t == lex.ItemStruct:
return formatStruct
case t == lex.ItemVar:
return formatVar
case t == lex.ItemOperator:
printOperator(f)
case t == lex.ItemArray:
if !printArray(f) {
return nil
}
case t == lex.ItemCase:
return formatCase
case t == lex.ItemEnum:
return formatEnum
default:
fmt.Fprintf(os.Stderr, "\nexpected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
return format
}
func (f *Formatter) printComment() {
fmt.Printf("%s", f.token.Val)
printNewline(f)
}
func formatFunction(f *Formatter) stateFn {
if f.token.Typ == lex.ItemFunction {
fmt.Printf("%s ", f.token.Val)
}
switch t := f.next().Typ; {
case t == lex.ItemEOF:
fmt.Fprintf(os.Stderr, "unexpected EOF wanted identifier\n")
return nil
case t == lex.ItemComment:
f.printComment()
case t == lex.ItemIdentifier:
printIdentifier(f)
if f.next().Typ == lex.ItemLeftParen {
printChar(f)
return format
}
}
fmt.Print("\n")
fmt.Fprintf(os.Stderr, "\nexpected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
// return formatFunction
}
func formatStruct(f *Formatter) stateFn {
if f.token.Typ == lex.ItemStruct {
printIdentifier(f)
}
switch t := f.next().Typ; {
case t == lex.ItemEOF:
fmt.Fprintf(os.Stderr, "unexpected EOF wanted identifier\n")
return nil
case t == lex.ItemComment:
f.printComment()
case t == lex.ItemIdentifier:
printIdentifier(f)
return format
default:
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
return formatStruct
}
func formatVar(f *Formatter) stateFn {
printIdentifier(f)
for notdone := true; notdone; {
if f.next().Typ == lex.ItemIdentifier {
printIdentifier(f)
if f.next().Typ == lex.ItemChar {
switch f.token.Val {
case ",":
printChar(f)
case ":":
printChar(f)
notdone = false
default:
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
} else {
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
} else {
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
}
switch f.next().Typ {
case lex.ItemIdentifier:
printIdentifier(f)
case lex.ItemArray:
if !printArray(f) {
return nil
}
default:
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
return format
}
func printIdentifier(f *Formatter) {
str := "%s"
switch f.peek().Val {
case "{", "}", "(", ")", "[", "]", "|", ",", ":", ";", ".":
default:
str += " "
}
fmt.Printf(str, f.token.Val)
}
func printOperator(f *Formatter) {
str := "%s"
switch f.token.Val {
case "|", "!":
case "+", "-":
switch f.pToken.Typ {
case lex.ItemLeftParen, lex.ItemOperator, lex.ItemReturn:
default:
str += " "
}
default:
str += " "
}
switch f.pToken.Val {
case ")", "]":
str = " " + str
}
fmt.Printf(str, f.token.Val)
}
func formatConditional(f *Formatter) stateFn {
switch f.token.Typ {
case lex.ItemIf, lex.ItemWhile, lex.ItemFor, lex.ItemSwitch:
tok := f.token.Val
if f.pToken.Typ == lex.ItemElse {
fmt.Print(" ")
}
if f.next().Typ != lex.ItemLeftParen {
fmt.Fprintf(os.Stderr, "expected parenthesis got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
fmt.Printf("%s (", tok)
f.parenDepth = 1
}
switch t := f.next().Typ; {
case t == lex.ItemEOF:
fmt.Fprintf(os.Stderr, "unexpected EOF wanted identifier\n")
return nil
case t == lex.ItemComment:
f.printComment()
case t == lex.ItemOperator:
printOperator(f)
case t == lex.ItemIdentifier, t == lex.ItemNumber, t == lex.ItemString, t == lex.ItemBool:
printIdentifier(f)
case isChar(t):
if f.token.Val == ";" {
fmt.Print("; ")
} else {
printChar(f)
}
switch f.token.Val {
case ")":
f.parenDepth--
if f.parenDepth == 0 {
if f.peek().Typ != lex.ItemLeftBrace {
f.scopeLevel[len(f.scopeLevel)-1]++
printNewline(f)
printTab(f)
}
return format
}
case "(":
f.parenDepth++
}
}
return formatConditional
}
func formatNewLine(f *Formatter) stateFn {
printNewline(f)
switch t := f.peek().Typ; {
case t == lex.ItemEOF:
return nil
case t == lex.ItemError:
fmt.Print("error:", f.token.Val)
return nil
case t == lex.ItemCase:
f.scopeLevel = f.scopeLevel[:len(f.scopeLevel)-1]
printTab(f)
case isChar(t):
switch f.nToken.Val {
case ":", ",":
fmt.Printf("%s ", f.token.Val)
case ";":
fmt.Print(f.token.Val)
f.next()
fmt.Print(f.token.Val)
if len(f.scopeLevel) > 0 {
f.scopeLevel[len(f.scopeLevel)-1] = 1
}
case "}":
// f.scopeLevel = f.scopeLevel[:len(f.scopeLevel)-1]
// printTab(f)
// fmt.Print("}")
f.next()
f.peek()
return formatRightBrace
default:
printTab(f)
}
return format
default:
printTab(f)
}
return format
}
func formatEnum(f *Formatter) stateFn {
printIdentifier(f)
if f.next().Typ != lex.ItemIdentifier {
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
printIdentifier(f)
if f.next().Typ != lex.ItemLeftBrace {
fmt.Fprintf(os.Stderr, "expected left brace got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
f.scopeLevel = append(f.scopeLevel, 1)
fmt.Print(" {")
f.newlineCount = -1
printNewline(f)
printTab(f)
return formatEnumIdent
}
func formatEnumIdent(f *Formatter) stateFn {
if f.next().Typ != lex.ItemIdentifier {
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
printIdentifier(f)
switch f.peek().Val {
case "=":
f.next()
printOperator(f)
if f.peek().Typ != lex.ItemNumber {
fmt.Fprintf(os.Stderr, "expected Number got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
f.next()
printIdentifier(f)
if f.peek().Typ == lex.ItemRightBrace {
return format
}
case "}":
return format
}
return formatEnumChar
}
func formatEnumChar(f *Formatter) stateFn {
if f.next().Val != "," {
fmt.Fprintf(os.Stderr, "expected Comma got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return nil
}
fmt.Print(",")
if f.peek().Typ == lex.ItemRightBrace {
return format
}
printNewline(f)
printTab(f)
return formatEnumIdent
}
func formatRightBrace(f *Formatter) stateFn {
f.scopeLevel = f.scopeLevel[:len(f.scopeLevel)-1]
f.newlineCount = -1
printNewline(f)
printTab(f)
fmt.Print("}")
switch f.peek().Typ {
case lex.ItemChar, lex.ItemElse, lex.ItemRightBrace:
return format
}
return formatNewLine
}
func formatCase(f *Formatter) stateFn {
printIdentifier(f)
if !printCase(f) {
return nil
}
if f.next().Val != ":" {
fmt.Fprintf(os.Stderr, "\nexpected \":\" got %s: %s %s\n", lex.Rkey[f.token.Typ], f.token.Val, f.pToken.Val)
return nil
}
fmt.Print(":")
f.scopeLevel = append(f.scopeLevel, 1)
return formatNewLine
}
func printCase(f *Formatter) bool {
switch f.next().Typ {
case lex.ItemLeftParen:
fmt.Print(" (")
if f.next().Typ != lex.ItemIdentifier {
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return false
}
printIdentifier(f)
if f.next().Typ != lex.ItemRightParen {
fmt.Fprintf(os.Stderr, "expected parenthesis got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return false
}
fmt.Print(")")
if f.next().Typ != lex.ItemIdentifier {
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return false
}
printIdentifier(f)
case lex.ItemIdentifier, lex.ItemNumber, lex.ItemString:
printIdentifier(f)
}
return true
}
func printArray(f *Formatter) bool {
if f.next().Val != "<" {
fmt.Fprintf(os.Stderr, "expected \"<\" got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return false
}
fmt.Printf("array<")
switch f.next().Typ {
case lex.ItemIdentifier:
fmt.Print(f.token.Val)
case lex.ItemArray:
printArray(f)
default:
fmt.Fprintf(os.Stderr, "expected Identifier got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return false
}
if f.next().Val != ">" {
fmt.Fprintf(os.Stderr, "expected \">\" got %s: %s\n", lex.Rkey[f.token.Typ], f.token.Val)
return false
}
fmt.Print(">")
return true
}
func printTab(f *Formatter) {
// fmt.Print(f.scopeLevel)
for _, t := range f.scopeLevel {
for i := 0; i < t; i++ {
fmt.Print("\t")
}
}
}
func isChar(t lex.ItemType) bool {
switch t {
case lex.ItemChar, lex.ItemLeftParen, lex.ItemRightParen, lex.ItemLeftBrace, lex.ItemRightBrace:
return true
default:
return false
}
}
func printChar(f *Formatter) stateFn {
switch f.token.Val {
case ":", ",":
fmt.Printf("%s ", f.token.Val)
case ";":
fmt.Print(";")
if len(f.scopeLevel) > 0 {
f.scopeLevel[len(f.scopeLevel)-1] = 1
}
return formatNewLine
case "{":
fmt.Print(" {")
f.scopeLevel = append(f.scopeLevel, 1)
f.newlineCount = -1
return formatNewLine
case "}":
return formatRightBrace
default:
fmt.Print(f.token.Val)
}
return format
}
func printNewline(f *Formatter) {
if f.newlineCount == -1 {
f.peek()
if f.newlineCount < 1 {
f.newlineCount = 1
}
}
f.peek()
if f.nToken.Typ != lex.ItemEOF {
for i := 0; i < f.newlineCount-1; i++ {
fmt.Print("\n")
}
fmt.Print("\n")
} else {
fmt.Print("\n")
}
}