/* Copyright (c) 2021 Arsen Musayelyan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. */ package scpt import ( "errors" "fmt" "os" "strconv" ) // Vars stores any variables set during script runtime var Vars = map[string]interface{}{} // FuncMap is a map of strings mapped to suitable script functions type FuncMap map[string]func(map[string]interface{}) (interface{}, error) // Funcs stores the functions allowed for use in a script var Funcs = FuncMap{ "str": toString, "num": parseNumber, "bool": parseBool, "break": setBreakLoop, "append": appendArray, "exit": scptExit, "return": setReturn, "print": scptPrint, } // Default function to convert unnamed argument to a string using fmt.Sprint func toString(args map[string]interface{}) (interface{}, error) { val, ok := args[""] if !ok { return nil, errors.New("no value provided") } return fmt.Sprint(val), nil } // Default function to parse unnamed argument to a number using strconv.ParseFloat func parseNumber(args map[string]interface{}) (interface{}, error) { val, ok := args[""].(string) if !ok { return nil, errors.New("no value provided") } return strconv.ParseFloat(val, 64) } // Default function to parse unnamed argument to a boolean using strconv.ParseBool func parseBool(args map[string]interface{}) (interface{}, error) { val, ok := args[""].(string) if !ok { return nil, errors.New("no value provided") } return strconv.ParseBool(val) } // Default function to set the breakLoop variable to true, breaking any loops that may be running func setBreakLoop(_ map[string]interface{}) (interface{}, error) { // If a loop is running if loopRunning { // Set breakLoop to true, breaking the loop on next cycle breakLoop = true } else { return nil, errors.New("break not inside loop") } return nil, nil } // Default function to set the breakLoop variable to true, breaking any loops that may be running func setReturn(args map[string]interface{}) (interface{}, error) { // If a loop is running if funcRunning { // Set breakLoop to true, breaking the loop on next cycle retValue = args[""] } else { return nil, errors.New("return not inside function") } return nil, nil } func scptExit(args map[string]interface{}) (interface{}, error) { exitCode, ok := args[""].(float64) if !ok { return nil, errors.New("exit requires an unnamed number argument") } os.Exit(int(exitCode)) return nil, nil } // Default function that returns an array with an appended element func appendArray(args map[string]interface{}) (interface{}, error) { // Attempt to get unnamed argument and assert as []interface{} val, ok := args[""].([]interface{}) if !ok { return nil, errors.New("cannot append to non-array object") } // Attempt to get items argument and assert as []interface{} items, ok := args["items"].([]interface{}) if !ok { return nil, errors.New("items argument invalid or not provided") } // For every item in items argument for _, item := range items { // Append to unnamed argument val = append(val, item) } // Return appended unnamed argument return val, nil } // Print message via fmt.Println func scptPrint(args map[string]interface{}) (interface{}, error) { // Get message val, ok := args[""] if !ok { return nil, errors.New("print requires an unnamed argument") } // Print message fmt.Println(val) return nil, nil }