package main
import (
"fmt"
"regexp"
"strconv"
"strings"
)
func indentMixCo( s string) ( string, error) {
pairs := map[ string] string{
"FOR" : "NEXT" ,
"IF" : "ENDIF" ,
}
level := 0
lines := strings.Split ( s, "\n " )
length, _ := strconv.Atoi ( lines[ 0 ] )
spaces := strings.Trim ( lines[ 1 ] , "\n " )
lines = lines[ 2 : ]
var stack [ ] string
var removed [ ] string
indented := false
for i := 0 ; i < length; i++ {
lines[ i] = strings.TrimLeft ( lines[ i] , "·»\t " )
for key, val := range pairs {
rOpen, _ := regexp.Compile ( fmt.Sprintf ( `^% v( $| \s) `, key) )
if rOpen.MatchString ( lines[ i] ) {
lines[ i] = strings.Repeat ( spaces, level) + lines[ i]
level++
stack = append( stack, key)
indented = true
}
rClose, _ := regexp.Compile ( fmt.Sprintf ( `^% v( $| \s) `, val) )
if rClose.MatchString ( lines[ i] ) {
level--
lines[ i] = strings.Repeat ( spaces, level) + lines[ i]
removed, stack = stack[ len( stack) - 1 : ] , stack[ : len( stack) - 1 ]
indented = true
if removed[ 0 ] != key {
return strings.Join ( lines, "\n " ) , fmt.Errorf ( "error: %v found on line %v but was looking for %v" , val, i+ 1 , pairs[ removed[ 0 ] ] )
}
}
}
if ! indented {
lines[ i] = strings.Repeat ( spaces, level) + lines[ i]
} else {
indented = false
}
}
return strings.Join ( lines, "\n " ) , nil
}
func main( ) {
input := `12
····
VAR I
·FOR I= 1 TO 31
»»»»IF ! ( I MOD 3 ) THEN
··PRINT "FIZZ"
··»»ENDIF
»»»»····IF ! ( I MOD 5 ) THEN
»»»»··PRINT "BUZZ"
··»»»»»»ENDIF
»»»»IF ( I MOD 3 ) && ( I MOD 5 ) THEN
······PRINT "FIZZBUZZ"
··»»ENDIF
»»»»·NEXT`
properFormat, err := indentMixCo( input)
if err != nil {
fmt.Println ( err)
fmt.Println ( properFormat)
} else {
fmt.Println ( properFormat)
}
}
cGFja2FnZSBtYWluCgppbXBvcnQgKAoJImZtdCIKCSJyZWdleHAiCgkic3RyY29udiIKCSJzdHJpbmdzIgopCgpmdW5jIGluZGVudE1peENvKHMgc3RyaW5nKSAoc3RyaW5nLCBlcnJvcikgewoJcGFpcnMgOj0gbWFwW3N0cmluZ11zdHJpbmd7CgkJIkZPUiI6ICJORVhUIiwKCQkiSUYiOiAgIkVORElGIiwKCX0KCWxldmVsIDo9IDAKCWxpbmVzIDo9IHN0cmluZ3MuU3BsaXQocywgIlxuIikKCWxlbmd0aCwgXyA6PSBzdHJjb252LkF0b2kobGluZXNbMF0pCglzcGFjZXMgOj0gc3RyaW5ncy5UcmltKGxpbmVzWzFdLCAiXG4iKQoJbGluZXMgPSBsaW5lc1syOl0KCXZhciBzdGFjayBbXXN0cmluZwoJdmFyIHJlbW92ZWQgW11zdHJpbmcKCWluZGVudGVkIDo9IGZhbHNlCglmb3IgaSA6PSAwOyBpIDwgbGVuZ3RoOyBpKysgewoJCWxpbmVzW2ldID0gc3RyaW5ncy5UcmltTGVmdChsaW5lc1tpXSwgIsK3wrtcdCIpCgkJZm9yIGtleSwgdmFsIDo9IHJhbmdlIHBhaXJzIHsKCQkJck9wZW4sIF8gOj0gcmVnZXhwLkNvbXBpbGUoZm10LlNwcmludGYoYF4ldigkfFxzKWAsIGtleSkpCgkJCWlmIHJPcGVuLk1hdGNoU3RyaW5nKGxpbmVzW2ldKSB7CgkJCQlsaW5lc1tpXSA9IHN0cmluZ3MuUmVwZWF0KHNwYWNlcywgbGV2ZWwpICsgbGluZXNbaV0KCQkJCWxldmVsKysKCQkJCXN0YWNrID0gYXBwZW5kKHN0YWNrLCBrZXkpCgkJCQlpbmRlbnRlZCA9IHRydWUKCQkJfQoJCQlyQ2xvc2UsIF8gOj0gcmVnZXhwLkNvbXBpbGUoZm10LlNwcmludGYoYF4ldigkfFxzKWAsIHZhbCkpCgkJCWlmIHJDbG9zZS5NYXRjaFN0cmluZyhsaW5lc1tpXSkgewoJCQkJbGV2ZWwtLQoJCQkJbGluZXNbaV0gPSBzdHJpbmdzLlJlcGVhdChzcGFjZXMsIGxldmVsKSArIGxpbmVzW2ldCgkJCQlyZW1vdmVkLCBzdGFjayA9IHN0YWNrW2xlbihzdGFjayktMTpdLCBzdGFja1s6bGVuKHN0YWNrKS0xXQoJCQkJaW5kZW50ZWQgPSB0cnVlCgkJCQlpZiByZW1vdmVkWzBdICE9IGtleSB7CgkJCQkJcmV0dXJuIHN0cmluZ3MuSm9pbihsaW5lcywgIlxuIiksIGZtdC5FcnJvcmYoImVycm9yOiAldiBmb3VuZCBvbiBsaW5lICV2IGJ1dCB3YXMgbG9va2luZyBmb3IgJXYiLCB2YWwsIGkrMSwgcGFpcnNbcmVtb3ZlZFswXV0pCgkJCQl9CgkJCX0KCQl9CgkJaWYgIWluZGVudGVkIHsKCQkJbGluZXNbaV0gPSBzdHJpbmdzLlJlcGVhdChzcGFjZXMsIGxldmVsKSArIGxpbmVzW2ldCgkJfSBlbHNlIHsKCQkJaW5kZW50ZWQgPSBmYWxzZQoJCX0KCX0KCXJldHVybiBzdHJpbmdzLkpvaW4obGluZXMsICJcbiIpLCBuaWwKfQoKZnVuYyBtYWluKCkgewoJaW5wdXQgOj0gYDEyCsK3wrfCt8K3ClZBUiBJCsK3Rk9SIEk9MSBUTyAzMQrCu8K7wrvCu0lGICEoSSBNT0QgMykgVEhFTgrCt8K3UFJJTlQgIkZJWloiCsK3wrfCu8K7RU5ESUYKwrvCu8K7wrvCt8K3wrfCt0lGICEoSSBNT0QgNSkgVEhFTgrCu8K7wrvCu8K3wrdQUklOVCAiQlVaWiIKwrfCt8K7wrvCu8K7wrvCu0VORElGCsK7wrvCu8K7SUYgKEkgTU9EIDMpICYmIChJIE1PRCA1KSBUSEVOCsK3wrfCt8K3wrfCt1BSSU5UICJGSVpaQlVaWiIKwrfCt8K7wrtFTkRJRgrCu8K7wrvCu8K3TkVYVGAKCglwcm9wZXJGb3JtYXQsIGVyciA6PSBpbmRlbnRNaXhDbyhpbnB1dCkKCWlmIGVyciAhPSBuaWwgewoJCWZtdC5QcmludGxuKGVycikKCQlmbXQuUHJpbnRsbihwcm9wZXJGb3JtYXQpCgl9IGVsc2UgewoJCWZtdC5QcmludGxuKHByb3BlckZvcm1hdCkKCX0KfQo=