SHS/ast/token.go
2020-07-18 14:40:35 -07:00

182 lines
3.8 KiB
Go

/* SHS: Syntactically Homogeneous Shell
* Copyright (C) 2019 Aidan Hahn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ast
import "fmt"
/* token_t is a tag that declares the type of the
* datum contained in a token
*/
type Token_t int
const (
LIST Token_t = iota
STRING Token_t = iota
NUMBER Token_t = iota
SYMBOL Token_t = iota
BOOL Token_t = iota
TRUE string = "T"
FALSE string = "F"
)
/* Contains a parsed lexeme
* and a pointer to the next parsed lexeme in the same scope
*/
type Token struct {
Next *Token
Tag Token_t
Position int
inner interface{}
}
/* Appends another token to the end of this token list
*/
func (t *Token) Append(arg *Token) {
if t.Next != nil {
t.Next.Append(arg)
} else {
t.Next = arg
}
}
/* Shallow Copy
* in case of a LIST,
* inner will point to the same list.
*/
func (t *Token) Copy() *Token {
return &Token{
Tag: t.Tag,
inner: t.inner,
Next: t.Next,
}
}
/* Print function which is better suited for repl.
* This one prints the SEXPRs as one would write them.
* Does not evaluate tokens.
*/
func (t *Token) String() string {
switch t.Tag {
case STRING:
return "\"" + t.inner.(string) + "\""
case NUMBER, BOOL:
return t.inner.(string)
case LIST:
repr := "("
if t.inner.(*Token) == nil {
return repr + ")"
}
for i := t.inner.(*Token); i != nil; i = i.Next {
repr = repr + i.String() + " "
}
// remove trailing space
return repr[:len(repr)-1] + ")"
case SYMBOL:
return "<" + t.inner.(string) + ">"
}
return "[UNKNOWN CELL TYPE]"
}
/* Returns a list held by a token
* returns nil if token holds no list
*/
func (t *Token) Expand() *Token {
if t.Tag != LIST {
return nil
}
return t.inner.(*Token)
}
/* Sets inner to a Token value
* returns false if parent token is not a list
* otherwise returns true
*/
func (t *Token) Direct(head *Token) bool {
if t.Tag != LIST {
return false
}
t.inner = head
return true
}
/* If token holds an atomic value
* (not a symbol or list)
* will return its value as a string
* else returns ""
*/
func (t *Token) Value() string {
if t.Tag == LIST {
return ""
}
return t.inner.(string)
}
/* returns an ascii representation of a token
*/
func (t *Token) FmtToken() string {
suffix := "->"
if t.Next == nil {
suffix = ""
}
switch t.Tag {
case LIST:
return fmt.Sprintf("(%s, [List])%s", "LIST", suffix)
default:
return fmt.Sprintf("(%s, %s)%s", GetTagAsStr(t.Tag), t.inner.(string), suffix)
}
}
/* Sets the string value for a non-list token
*/
func (t *Token) Set(arg string) bool {
if t.Tag == LIST {
return false
}
t.inner = arg
return true
}
/* Returns a tag in text
*/
func GetTagAsStr(tag Token_t) string {
switch tag {
case LIST:
return "LIST"
case STRING:
return "STRING"
case BOOL:
return "BOOL"
case NUMBER:
return "NUMBER"
case SYMBOL:
return "SYMBOL"
}
return "UNKNOWN"
}