This repository has been archived on 2024-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
arf/parser/tree-tostring.go

447 lines
10 KiB
Go

package parser
import "fmt"
import "sort"
import "git.tebibyte.media/arf/arf/lexer"
func doIndent (indent int, input ...string) (output string) {
for index := 0; index < indent; index ++ {
output += "\t"
}
for _, inputSection := range input {
output += inputSection
}
return
}
func sortMapKeysAlphabetically[KEY_TYPE any] (
unsortedMap map[string] KEY_TYPE,
) (
sortedKeys []string,
) {
sortedKeys = make([]string, len(unsortedMap))
index := 0
for key, _ := range unsortedMap {
sortedKeys[index] = key
index ++
}
sort.Strings(sortedKeys)
return
}
func (tree SyntaxTree) ToString (indent int) (output string) {
output += doIndent(indent, ":arf\n")
if tree.author != "" {
output += doIndent(indent, "author '", tree.author, "'\n")
}
if tree.license != "" {
output += doIndent(indent, "license '", tree.license, "'\n")
}
for _, name := range sortMapKeysAlphabetically(tree.requires) {
require := tree.requires[name]
output += doIndent(indent, "require '", require, "'\n")
}
output += doIndent(indent, "---\n")
sectionKeys := sortMapKeysAlphabetically(tree.sections)
for _, name := range sectionKeys {
output += tree.sections[name].ToString(indent)
}
return
}
func (identifier Identifier) ToString () (output string) {
for index, trailItem := range identifier.trail {
if index > 0 {
output += "."
}
output += trailItem
}
return
}
func (what Type) ToString () (output string) {
if what.kind == TypeKindNil {
output += "NIL-TYPE"
return
}
if what.kind == TypeKindBasic {
output += what.name.ToString()
} else {
output += "{"
output += what.points.ToString()
if what.kind == TypeKindVariableArray {
output += " .."
}
output += "}"
}
if what.length > 1 {
output += fmt.Sprint(":", what.length)
}
if what.mutable {
output += ":mut"
}
return
}
func (declaration Declaration) ToString () (output string) {
output += declaration.name + ":"
output += declaration.what.ToString()
return
}
func (list List) ToString (indent int, breakline bool) (output string) {
if !breakline { indent = 0 }
output += doIndent(indent, "(")
if breakline { output += "\n" }
for index, argument := range list.arguments {
if !breakline && index > 0 { output += " "}
output += argument.ToString(indent, breakline)
}
output += doIndent(indent, ")")
if breakline { output += "\n" }
return
}
func (argument Argument) ToString (indent int, breakLine bool) (output string) {
if !breakLine { indent = 0 }
if argument.kind == ArgumentKindNil {
output += "NIL-ARGUMENT"
if breakLine { output += "\n" }
return
}
switch argument.kind {
case ArgumentKindPhrase:
output += argument.value.(Phrase).ToString (
indent,
breakLine)
case ArgumentKindList:
output += argument.value.(List).ToString(indent, breakLine)
case ArgumentKindDereference:
output += argument.value.(Dereference).ToString(indent)
case ArgumentKindIdentifier:
output += doIndent (
indent,
argument.value.(Identifier).ToString())
if breakLine { output += "\n" }
case ArgumentKindDeclaration:
output += doIndent (
indent,
argument.value.(Declaration).ToString())
if breakLine { output += "\n" }
case ArgumentKindInt, ArgumentKindUInt, ArgumentKindFloat:
output += doIndent(indent, fmt.Sprint(argument.value))
if breakLine { output += "\n" }
case ArgumentKindString:
output += doIndent (
indent,
"'" + argument.value.(string) + "'")
if breakLine { output += "\n" }
}
return
}
func (section DataSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"data ",
section.permission.ToString(), " ",
section.name, ":",
section.what.ToString(), "\n")
if section.argument.kind != ArgumentKindNil {
output += section.argument.ToString(indent + 1, true)
}
if section.external {
output += doIndent(indent + 1, "external\n")
}
return
}
func (member TypeSectionMember) ToString (indent int) (output string) {
output += doIndent(indent, member.permission.ToString())
output += " " + member.name
if member.what.kind != TypeKindNil {
output += ":" + member.what.ToString()
}
if member.argument.kind != ArgumentKindNil {
output += " " + member.argument.ToString(indent, false)
}
if member.bitWidth > 0 {
output += fmt.Sprint(" & ", member.bitWidth)
}
output += "\n"
return
}
func (section TypeSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"type ",
section.permission.ToString(), " ",
section.name, ":",
section.what.ToString(), "\n")
if section.argument.kind != ArgumentKindNil {
output += section.argument.ToString(indent + 1, true)
}
for _, member := range section.members {
output += member.ToString(indent + 1)
}
return
}
func (section EnumSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"enum ",
section.permission.ToString(), " ",
section.name, ":",
section.what.ToString(), "\n")
for _, member := range section.members {
output += doIndent(indent + 1, "- ", member.name)
if member.argument.kind != ArgumentKindNil {
output += " " + member.argument.ToString(indent, false)
}
output += "\n"
}
return
}
func (section FaceSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"face ",
section.permission.ToString(), " ",
section.name, ":",
section.inherits.ToString(), "\n")
if section.kind == FaceKindType {
for _, name := range sortMapKeysAlphabetically(section.behaviors) {
behavior := section.behaviors[name]
output += behavior.ToString(indent + 1)
}
} else if section.kind == FaceKindFunc {
for _, inputItem := range section.inputs {
output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n")
}
for _, outputItem := range section.outputs {
output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n")
}
}
return
}
func (behavior FaceBehavior) ToString (indent int) (output string) {
output += doIndent(indent, behavior.name, "\n")
for _, inputItem := range behavior.inputs {
output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n")
}
for _, outputItem := range behavior.outputs {
output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n")
}
return
}
func (dereference Dereference) ToString (indent int) (output string) {
output += "{"
output += dereference.argument.ToString(indent, false)
if dereference.offset != 0 {
output += fmt.Sprint(" ", dereference.offset)
}
output += "}"
return
}
func (phrase Phrase) ToString (indent int, ownLine bool) (output string) {
if ownLine {
output += doIndent(indent)
}
output += "["
switch phrase.kind {
case PhraseKindCase:
output += ":"
case PhraseKindAssign:
output += "="
case PhraseKindOperator:
switch phrase.operator {
case lexer.TokenKindColon:
output += ":"
case lexer.TokenKindPlus:
output += "+"
case lexer.TokenKindMinus:
output += "-"
case lexer.TokenKindIncrement:
output += "++"
case lexer.TokenKindDecrement:
output += "--"
case lexer.TokenKindAsterisk:
output += "*"
case lexer.TokenKindSlash:
output += "/"
case lexer.TokenKindExclamation:
output += "!"
case lexer.TokenKindPercent:
output += "%"
case lexer.TokenKindPercentAssignment:
output += "%="
case lexer.TokenKindTilde:
output += "~"
case lexer.TokenKindTildeAssignment:
output += "~="
case lexer.TokenKindAssignment:
output += "="
case lexer.TokenKindEqualTo:
output += "=="
case lexer.TokenKindNotEqualTo:
output += "!="
case lexer.TokenKindLessThanEqualTo:
output += "<="
case lexer.TokenKindLessThan:
output += "<"
case lexer.TokenKindLShift:
output += "<<"
case lexer.TokenKindLShiftAssignment:
output += "<<="
case lexer.TokenKindGreaterThan:
output += ">"
case lexer.TokenKindGreaterThanEqualTo:
output += ">="
case lexer.TokenKindRShift:
output += ">>"
case lexer.TokenKindRShiftAssignment:
output += ">>="
case lexer.TokenKindBinaryOr:
output += "|"
case lexer.TokenKindBinaryOrAssignment:
output += "|="
case lexer.TokenKindLogicalOr:
output += "||"
case lexer.TokenKindBinaryAnd:
output += "&"
case lexer.TokenKindBinaryAndAssignment:
output += "&="
case lexer.TokenKindLogicalAnd:
output += "&&"
case lexer.TokenKindBinaryXor:
output += "^"
case lexer.TokenKindBinaryXorAssignment:
output += "^="
}
default:
output += phrase.command.ToString(0, false)
}
for _, argument := range phrase.arguments {
output += " " + argument.ToString(0, false)
}
output += "]"
if len(phrase.returnees) > 0 {
output += " ->"
for _, returnItem := range phrase.returnees {
output += " " + returnItem.ToString(0, false)
}
}
if ownLine {
output += "\n"
output += phrase.block.ToString(indent + 1)
} else if len(phrase.block) > 0 {
output += "NON-BLOCK-LEVEL-PHRASE-HAS-BLOCK"
}
return
}
func (funcOutput FuncOutput) ToString (indent int) (output string) {
output += doIndent(indent + 1)
output += "< " + funcOutput.Declaration.ToString()
if funcOutput.argument.kind != ArgumentKindNil {
output += " " + funcOutput.argument.ToString(indent, false)
}
output += "\n"
return
}
func (block Block) ToString (indent int) (output string) {
for _, phrase := range block {
output += phrase.ToString(indent, true)
}
return
}
func (section FuncSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"func ",
section.permission.ToString(), " ",
section.name, "\n")
if section.receiver != nil {
output += doIndent (
indent + 1,
"@ ", section.receiver.ToString(), "\n")
}
for _, inputItem := range section.inputs {
output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n")
}
for _, outputItem := range section.outputs {
output += outputItem.ToString(indent)
}
output += doIndent(indent + 1, "---\n")
if section.external {
output += doIndent(indent + 1, "external\n")
}
output += section.root.ToString(indent + 1)
return
}