SHS/ast/var_table.go
2020-06-30 20:27:12 -07:00

124 lines
3.4 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 (
"os"
"fmt"
"math"
"strconv"
"strings"
"gitlab.com/whom/shs/log"
)
// Trigger this if you are using this for a shell
var SyncTablesWithOSEnviron = false
type VarTable *map[string]*Token
func GetVar(arg string, vt VarTable) *Token {
val, ok := (*vt)[arg]
if !ok {
if !SyncTablesWithOSEnviron {
return nil
}
e := os.Getenv(arg)
if e != "" {
t := &Token{inner: e}
if StrIsNumber(e) {
t.Tag = NUMBER
} else {
t.Tag = STRING
}
SetVar(arg, t, vt)
return t
}
return nil
}
return val
}
// TODO: this could be much more optimal
// TODO: Make sure variables are evaluated before being set
// probably a stdlib thing
func SetVar(variable string, value *Token, vt VarTable) {
(*vt)[variable] = value
if SyncTablesWithOSEnviron &&
(value.Tag == NUMBER || value.Tag == STRING) {
token := value.Value()
if value.Tag == NUMBER {
// make sure its an int
a, err := strconv.ParseFloat(token, 64)
if err == nil && math.Mod(a, 1.0) == 0 {
token = fmt.Sprintf("%d", int(a))
}
}
os.Setenv(variable, token)
}
}
// Library represents variables defined in inner scope
// It is assumed library is ordered from innermost scope to outermost scope
func GetVarFromTables(arg string, library []VarTable) *Token {
var res *Token
res = nil
for i := 0; i < len(library); i += 1 {
res = GetVar(arg, library[i])
if res != nil {
// TODO: Log scope res was found in?
break
}
}
return res
}
func InitVarTable(table VarTable) {
if !SyncTablesWithOSEnviron {
return
}
for _, val := range os.Environ() {
variable := strings.Split(val, "=")
t := &Token{inner: variable[1]}
if StrIsNumber(variable[1]) {
t.Tag = NUMBER
} else {
t.Tag = STRING
}
if variable[0] == "HOME" {
SetVar('~', t, table)
}
SetVar(variable[0], t, table)
}
}
// Dont do this on var tables youve already called InitVarTable on.... please....
// This will pull currently contained variables OUT of the operating env
func DeleteVarTable(table VarTable) {
for key, _ := range (*table) {
// from what I can tell, theres not much we can do if this fails
err := os.Unsetenv(key)
if err != nil {
log.Log(log.DEBUG, "Failed to remove " + key + " from env: " + err.Error(), "vartable")
}
}
}