mirror of
https://github.com/Open-Argon/argon-v3.git
synced 2025-12-06 00:46:07 +00:00
add create functions
This commit is contained in:
23
package.json
23
package.json
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "argon-v3",
|
||||
"version": "1.0.0",
|
||||
"description": "The go to language for mathematicians!",
|
||||
"scripts": {
|
||||
"build": "mkdir -p build && go build -o build/argon ./src",
|
||||
"dev": "nodemon -x go run ./src/. --signal SIGKILL -e go --verbose",
|
||||
"start": "go run ./src/."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Ugric/argon-v3.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Ugric/argon-v3/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Ugric/argon-v3#readme",
|
||||
"dependencies": {
|
||||
"nodemon": "^2.0.20"
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ ARGON 3 is a math-driven programming language designed to make code easy to read
|
||||
- Lightweight: The Argon 3 interpreter is small and doesn't require a lot of system resources to run.
|
||||
|
||||
## 💻 Installation
|
||||
As of now, Argon 3 does not have an installer. Feel free to clone this repo and run the `build` file for your plateform. the build will be found in `bin/Argon-v3(.exe)`.
|
||||
As of now, Argon 3 does not have an installer. Feel free to clone this repo and run the `build` file for your plateform. the build will be found in `bin/argon(.exe)`.
|
||||
|
||||
## 📖 Usage
|
||||
|
||||
|
||||
31
src/brackets.go
Normal file
31
src/brackets.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
|
||||
var bracketsCompile = makeRegex(`( *)\((.|\n)+\)( *)`)
|
||||
|
||||
type brackets struct {
|
||||
VAL any
|
||||
line int
|
||||
code string
|
||||
path string
|
||||
}
|
||||
|
||||
func isBrackets(code UNPARSEcode) bool {
|
||||
return bracketsCompile.MatchString(code.code)
|
||||
}
|
||||
|
||||
func parseBrackets(code UNPARSEcode, index int, codeline []UNPARSEcode) (brackets, bool, ArErr, int) {
|
||||
resp, worked, err, i := translateVal(UNPARSEcode{
|
||||
code: strings.TrimSpace(code.code)[1 : len(code.code)-1],
|
||||
realcode: code.realcode,
|
||||
line: code.line,
|
||||
path: code.path,
|
||||
}, index, codeline, false)
|
||||
return brackets{
|
||||
VAL: resp,
|
||||
line: code.line,
|
||||
code: code.realcode,
|
||||
path: code.path,
|
||||
}, worked, err, i
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type builtinFunc struct {
|
||||
@@ -25,9 +25,17 @@ func ArgonAdd(args ...any) (any, ArErr) {
|
||||
}, args), ArErr{}
|
||||
}
|
||||
func ArgonDiv(args ...any) (any, ArErr) {
|
||||
return reduce(func(x any, y any) any {
|
||||
return newNumber().Quo(y.(number), x.(number))
|
||||
}, args), ArErr{}
|
||||
if len(args) == 0 {
|
||||
return nil, ArErr{TYPE: "Division Error", message: "Cannot divide nothing", EXISTS: true}
|
||||
}
|
||||
output := args[0].(number)
|
||||
for i := 1; i < len(args); i++ {
|
||||
if args[i].(number).Cmp(newNumber()) == 0 {
|
||||
return nil, ArErr{TYPE: "Division Error", message: "Cannot divide by zero", EXISTS: true}
|
||||
}
|
||||
output = newNumber().Quo(output, args[i].(number))
|
||||
}
|
||||
return output, ArErr{}
|
||||
}
|
||||
|
||||
func ArgonMult(args ...any) (any, ArErr) {
|
||||
@@ -36,14 +44,61 @@ func ArgonMult(args ...any) (any, ArErr) {
|
||||
}, args), ArErr{}
|
||||
}
|
||||
|
||||
func ArgonSleep(args ...any) (any, ArErr) {
|
||||
func ArgonInput(args ...any) (any, ArErr) {
|
||||
// allow a message to be passed in as an argument
|
||||
if len(args) > 0 {
|
||||
float, _ := args[0].(number).Float64()
|
||||
time.Sleep(time.Duration(float*1000000000) * time.Nanosecond)
|
||||
fmt.Print(anyToArgon(args[0], false))
|
||||
}
|
||||
return nil, ArErr{}
|
||||
var input string
|
||||
fmt.Scanln(&input)
|
||||
return input, ArErr{}
|
||||
}
|
||||
|
||||
func ArgonTimestamp(args ...any) (any, ArErr) {
|
||||
return newNumber().Quo(newNumber().SetInt64(time.Now().UnixNano()), newNumber().SetInt64(1000000000)), ArErr{}
|
||||
func ArgonNumber(args ...any) (any, ArErr) {
|
||||
if len(args) == 0 {
|
||||
return newNumber(), ArErr{}
|
||||
}
|
||||
switch x := args[0].(type) {
|
||||
case string:
|
||||
if !numberCompile.MatchString(x) {
|
||||
return nil, ArErr{TYPE: "Number Error", message: "Cannot convert type '" + typeof(x) + "' to a number", EXISTS: true}
|
||||
}
|
||||
N, _ := newNumber().SetString(x)
|
||||
return N, ArErr{}
|
||||
case number:
|
||||
return x, ArErr{}
|
||||
case bool:
|
||||
if x {
|
||||
return newNumber().SetInt64(1), ArErr{}
|
||||
}
|
||||
return newNumber().SetInt64(0), ArErr{}
|
||||
case nil:
|
||||
return newNumber(), ArErr{}
|
||||
}
|
||||
|
||||
return nil, ArErr{TYPE: "Number Error", message: "Cannot convert " + typeof(args[0]) + " to a number", EXISTS: true}
|
||||
}
|
||||
|
||||
func ArgonSqrt(a ...any) (any, ArErr) {
|
||||
if len(a) == 0 {
|
||||
return nil, ArErr{TYPE: "sqrt", message: "sqrt takes 1 argument",
|
||||
EXISTS: true}
|
||||
}
|
||||
r := a[0].(number)
|
||||
|
||||
if r.Sign() < 0 {
|
||||
return nil, ArErr{TYPE: "sqrt", message: "sqrt takes a positive number",
|
||||
EXISTS: true}
|
||||
}
|
||||
|
||||
var x big.Float
|
||||
x.SetPrec(30) // I didn't figure out the 'Prec' part correctly, read the docs more carefully than I did and experiement
|
||||
x.SetRat(r)
|
||||
|
||||
var s big.Float
|
||||
s.SetPrec(15)
|
||||
s.Sqrt(&x)
|
||||
|
||||
r, _ = s.Rat(nil)
|
||||
return r, ArErr{}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
package main
|
||||
|
||||
var vars = map[string]variableValue{}
|
||||
var vars = map[string]any{}
|
||||
|
||||
func init() {
|
||||
vars["log"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: builtinFunc{"log", ArgonLog},
|
||||
}
|
||||
vars["add"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: builtinFunc{"add", ArgonAdd},
|
||||
}
|
||||
vars["div"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: builtinFunc{"div", ArgonDiv},
|
||||
}
|
||||
vars["true"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: true,
|
||||
}
|
||||
vars["false"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: false,
|
||||
}
|
||||
vars["mult"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: builtinFunc{"mult", ArgonMult},
|
||||
}
|
||||
vars["time"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: ArMap{"snooze": builtinFunc{"snooze", ArgonSleep}, "now": builtinFunc{"now", ArgonTimestamp}},
|
||||
vars["log"] = builtinFunc{"log", ArgonLog}
|
||||
vars["add"] = builtinFunc{"add", ArgonAdd}
|
||||
vars["div"] = builtinFunc{"div", ArgonDiv}
|
||||
vars["true"] = true
|
||||
vars["false"] = false
|
||||
vars["null"] = nil
|
||||
vars["input"] = builtinFunc{"input", ArgonInput}
|
||||
vars["number"] = builtinFunc{"number", ArgonNumber}
|
||||
vars["mult"] = builtinFunc{"mult", ArgonMult}
|
||||
vars["length"] = builtinFunc{"length", func(a ...any) (any, ArErr) {
|
||||
switch x := a[0].(type) {
|
||||
case string:
|
||||
return len(x), ArErr{}
|
||||
case ArMap:
|
||||
return len(x), ArErr{}
|
||||
}
|
||||
return nil, ArErr{TYPE: "TypeError", message: "Cannot get length of " + typeof(a[0]), EXISTS: true}
|
||||
}}
|
||||
vars["time"] = ArTime
|
||||
pi, _ := newNumber().SetString("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989")
|
||||
vars["PI"] = variableValue{
|
||||
EXISTS: true,
|
||||
VAL: pi,
|
||||
}
|
||||
vars["PI"] = pi
|
||||
vars["π"] = pi
|
||||
e, _ := newNumber().SetString("2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354")
|
||||
vars["e"] = e
|
||||
vars["sqrt"] = builtinFunc{"sqrt", ArgonSqrt}
|
||||
vars["√"] = builtinFunc{"sqrt", ArgonSqrt}
|
||||
}
|
||||
|
||||
21
src/call.go
21
src/call.go
@@ -1,10 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var callCompile = makeRegex("( *).+\\(.*\\)( *)")
|
||||
var callCompile = makeRegex("( *)(.|\n)+\\((.|\n)*\\)( *)")
|
||||
|
||||
type call struct {
|
||||
callable any
|
||||
@@ -60,8 +61,9 @@ func runCall(c call, stack stack) (any, ArErr) {
|
||||
return nil, err
|
||||
}
|
||||
args := []any{}
|
||||
level := append(stack, map[string]any{})
|
||||
for _, arg := range c.args {
|
||||
resp, err := runVal(arg, stack)
|
||||
resp, err := runVal(arg, level)
|
||||
if err.EXISTS {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,9 +71,20 @@ func runCall(c call, stack stack) (any, ArErr) {
|
||||
}
|
||||
switch x := callable.(type) {
|
||||
case builtinFunc:
|
||||
return x.FUNC(args...)
|
||||
resp, err := x.FUNC(args...)
|
||||
if err.EXISTS {
|
||||
err = ArErr{err.TYPE, err.message, c.line, c.path, c.code, true}
|
||||
}
|
||||
return resp, err
|
||||
case Callable:
|
||||
return nil, ArErr{"Runtime Error", "cannot call a class", c.line, c.path, c.code, true}
|
||||
if len(x.params) != len(args) {
|
||||
return nil, ArErr{"Runtime Error", "expected " + fmt.Sprint(len(x.params)) + " arguments, got " + fmt.Sprint(len(args)), c.line, c.path, c.code, true}
|
||||
}
|
||||
level := map[string]any{}
|
||||
for i, param := range x.params {
|
||||
level[param] = args[i]
|
||||
}
|
||||
return runVal(x.run, append(stack, level))
|
||||
}
|
||||
return nil, ArErr{"Runtime Error", "type '" + typeof(callable) + "' is not callable", c.line, c.path, c.code, true}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ package main
|
||||
type Callable struct {
|
||||
name string
|
||||
params []string
|
||||
code []any
|
||||
run any
|
||||
code string
|
||||
stack stack
|
||||
line int
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var commentCompile = makeRegex(".*//.*")
|
||||
var commentCompile = makeRegex("(.|\n)*//(.|\n)*")
|
||||
|
||||
func isComment(code UNPARSEcode) bool {
|
||||
return commentCompile.MatchString(code.code)
|
||||
|
||||
@@ -15,9 +15,11 @@ type ArErr struct {
|
||||
}
|
||||
|
||||
func panicErr(err ArErr) {
|
||||
if err.code != "" && err.line != 0 && err.path != "" {
|
||||
fmt.Println(" File:", err.path+":"+fmt.Sprint(err.line))
|
||||
fmt.Println(" " + err.code)
|
||||
fmt.Println()
|
||||
}
|
||||
fmt.Println(err.TYPE+":", err.message)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -98,7 +98,8 @@ func importMod(realpath string, origin string, main bool) ArErr {
|
||||
if translationerr.EXISTS {
|
||||
return translationerr
|
||||
}
|
||||
_, runimeErr := run(translated, stack{vars})
|
||||
global := map[string]any{}
|
||||
_, runimeErr := run(translated, stack{vars, global})
|
||||
if runimeErr.EXISTS {
|
||||
return runimeErr
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
// args without the program path
|
||||
var Args = os.Args[1:]
|
||||
|
||||
type stack = []map[string]variableValue
|
||||
type stack = []map[string]any
|
||||
|
||||
func main() {
|
||||
ex, e := os.Getwd()
|
||||
|
||||
20
src/map.go
20
src/map.go
@@ -7,7 +7,12 @@ import (
|
||||
|
||||
type ArMap = map[any]any
|
||||
|
||||
var mapGetCompile = makeRegex(".+\\.([a-zA-Z_])([a-zA-Z0-9_])*( *)")
|
||||
type ArClass struct {
|
||||
value any
|
||||
MAP ArMap
|
||||
}
|
||||
|
||||
var mapGetCompile = makeRegex("(.|\n)+\\.([a-zA-Z_])([a-zA-Z0-9_])*( *)")
|
||||
|
||||
type ArMapGet struct {
|
||||
VAL any
|
||||
@@ -39,6 +44,19 @@ func mapGet(r ArMapGet, stack stack) (any, ArErr) {
|
||||
}
|
||||
}
|
||||
return m[key], ArErr{}
|
||||
case ArClass:
|
||||
if _, ok := m.MAP[key]; !ok {
|
||||
return nil, ArErr{
|
||||
"KeyError",
|
||||
"key '" + fmt.Sprint(key) + "' not found",
|
||||
r.line,
|
||||
r.path,
|
||||
r.code,
|
||||
true,
|
||||
}
|
||||
}
|
||||
return m.MAP[key], ArErr{}
|
||||
|
||||
}
|
||||
return nil, ArErr{
|
||||
"TypeError",
|
||||
|
||||
31
src/negative.go
Normal file
31
src/negative.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import "strings"
|
||||
|
||||
var negativeCompile = makeRegex(`( *)-(.|\n)+( *)`)
|
||||
|
||||
type negative struct {
|
||||
VAL any
|
||||
line int
|
||||
code string
|
||||
path string
|
||||
}
|
||||
|
||||
func isNegative(code UNPARSEcode) bool {
|
||||
return negativeCompile.MatchString(code.code)
|
||||
}
|
||||
|
||||
func parseNegative(code UNPARSEcode, index int, codeline []UNPARSEcode) (negative, bool, ArErr, int) {
|
||||
resp, worked, err, i := translateVal(UNPARSEcode{
|
||||
code: strings.TrimSpace(code.code)[1:],
|
||||
realcode: code.realcode,
|
||||
line: code.line,
|
||||
path: code.path,
|
||||
}, index, codeline, false)
|
||||
return negative{
|
||||
VAL: resp,
|
||||
line: code.line,
|
||||
code: code.realcode,
|
||||
path: code.path,
|
||||
}, worked, err, i
|
||||
}
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
)
|
||||
|
||||
type translateNumber struct {
|
||||
number
|
||||
number number
|
||||
code string
|
||||
line int
|
||||
}
|
||||
|
||||
var numberCompile = makeRegex("( *)(\\-)?((([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
||||
var binaryCompile = makeRegex("( *)(0b[10]+(.[10]+)?(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
||||
var hexCompile = makeRegex("( *)(0x[a-fA-F0-9]+(.[a-fA-F0-9]+)?)( *)")
|
||||
var octalCompile = makeRegex("( *)(0o[0-7]+(.[0-7]+)?(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
||||
var numberCompile = makeRegex("( *)(-)?((([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
||||
var binaryCompile = makeRegex("( *)(-)?(0b[10]+(.\\[10]+)?(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
||||
var hexCompile = makeRegex("( *)(-)?(0x[a-fA-F0-9]+(\\.[a-fA-F0-9]+)?)( *)")
|
||||
var octalCompile = makeRegex("( *)(-)?(0o[0-7]+(\\.[0-7]+)?(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
||||
|
||||
// a number type
|
||||
type number = *big.Rat
|
||||
@@ -25,11 +25,6 @@ func newNumber() *big.Rat {
|
||||
return new(big.Rat)
|
||||
}
|
||||
|
||||
// converts a string into a number
|
||||
func stringToNumber(str string) (*big.Rat, bool) {
|
||||
return newNumber().SetString(str)
|
||||
}
|
||||
|
||||
func isNumber(code UNPARSEcode) bool {
|
||||
return numberCompile.MatchString(code.code) || binaryCompile.MatchString(code.code) || hexCompile.MatchString(code.code) || octalCompile.MatchString(code.code)
|
||||
}
|
||||
@@ -89,10 +84,7 @@ var subscript = map[byte]string{
|
||||
}
|
||||
|
||||
// returns translateNumber, success, error
|
||||
func parseNumber(code UNPARSEcode) (translateNumber, bool, ArErr, int) {
|
||||
func parseNumber(code UNPARSEcode) (number, bool, ArErr, int) {
|
||||
output, _ := newNumber().SetString(strings.TrimSpace(code.code))
|
||||
return translateNumber{
|
||||
number: output,
|
||||
line: code.line,
|
||||
}, true, ArErr{}, 1
|
||||
return output, true, ArErr{}, 1
|
||||
}
|
||||
|
||||
35
src/run.go
35
src/run.go
@@ -2,17 +2,44 @@ package main
|
||||
|
||||
// returns (number|string|nil), error
|
||||
func runVal(line any, stack stack) (any, ArErr) {
|
||||
if len(stack) > 500 {
|
||||
return nil, ArErr{
|
||||
TYPE: "Stack overflow",
|
||||
message: "the stack has exceeded 500 levels",
|
||||
EXISTS: true,
|
||||
}
|
||||
}
|
||||
switch x := line.(type) {
|
||||
case translateNumber:
|
||||
return (x.number), ArErr{}
|
||||
case translateString:
|
||||
return (x.str), ArErr{}
|
||||
case number:
|
||||
return x, ArErr{}
|
||||
case string:
|
||||
return x, ArErr{}
|
||||
case call:
|
||||
return runCall(x, stack)
|
||||
case accessVariable:
|
||||
return readVariable(x, stack)
|
||||
case ArMapGet:
|
||||
return mapGet(x, stack)
|
||||
case ArClass:
|
||||
return x.MAP, ArErr{}
|
||||
case setVariable:
|
||||
return setVariableValue(x, stack)
|
||||
case negative:
|
||||
resp, err := runVal(x.VAL, stack)
|
||||
if err.EXISTS {
|
||||
return nil, err
|
||||
}
|
||||
switch y := resp.(type) {
|
||||
case number:
|
||||
return newNumber().Neg(y), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "TypeError",
|
||||
message: "cannot negate a non-number",
|
||||
EXISTS: true,
|
||||
}
|
||||
case brackets:
|
||||
return runVal(x.VAL, stack)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -32,16 +32,13 @@ func unquoted(
|
||||
}
|
||||
|
||||
// returns translateString, success, error
|
||||
func parseString(code UNPARSEcode) (translateString, bool, ArErr, int) {
|
||||
func parseString(code UNPARSEcode) (string, bool, ArErr, int) {
|
||||
trim := strings.Trim(code.code, " ")
|
||||
|
||||
unquoted, err := unquoted(trim)
|
||||
if err != nil {
|
||||
return translateString{}, false, ArErr{"Syntax Error", "invalid string", code.line, code.path, code.realcode, true}, 1
|
||||
return "", false, ArErr{"Syntax Error", "invalid string", code.line, code.path, code.realcode, true}, 1
|
||||
}
|
||||
|
||||
return translateString{
|
||||
str: unquoted,
|
||||
line: code.line,
|
||||
}, true, ArErr{}, 1
|
||||
return unquoted, true, ArErr{}, 1
|
||||
}
|
||||
|
||||
216
src/time.go
Normal file
216
src/time.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var MicroSeconds = newNumber().SetInt64(1000000)
|
||||
|
||||
func ArTimeClass(N time.Time) ArClass {
|
||||
return ArClass{
|
||||
newNumber().Quo(newNumber().SetInt64(N.UnixMicro()), MicroSeconds),
|
||||
ArMap{
|
||||
"year": builtinFunc{
|
||||
"year",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.Year())), ArErr{}
|
||||
},
|
||||
},
|
||||
"month": builtinFunc{
|
||||
"month",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return N.Month().String(), ArErr{}
|
||||
},
|
||||
},
|
||||
"day": builtinFunc{
|
||||
"day",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.Day())), ArErr{}
|
||||
},
|
||||
},
|
||||
"hour": builtinFunc{
|
||||
"hour",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.Hour())), ArErr{}
|
||||
},
|
||||
},
|
||||
"minute": builtinFunc{
|
||||
"minute",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.Minute())), ArErr{}
|
||||
},
|
||||
},
|
||||
"second": builtinFunc{
|
||||
"second",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.Second())), ArErr{}
|
||||
},
|
||||
},
|
||||
"nanosecond": builtinFunc{
|
||||
"nanosecond",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.Nanosecond())), ArErr{}
|
||||
},
|
||||
},
|
||||
"weekday": builtinFunc{
|
||||
"weekday",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return N.Weekday().String(), ArErr{}
|
||||
},
|
||||
},
|
||||
"yearDay": builtinFunc{
|
||||
"yearDay",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(int64(N.YearDay())), ArErr{}
|
||||
},
|
||||
},
|
||||
"unix": builtinFunc{
|
||||
"unix",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(N.Unix()), ArErr{}
|
||||
},
|
||||
},
|
||||
"unixNano": builtinFunc{
|
||||
"unixNano",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(N.UnixNano()), ArErr{}
|
||||
},
|
||||
},
|
||||
"unixMilli": builtinFunc{
|
||||
"unixMilli",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(N.UnixMilli()), ArErr{}
|
||||
},
|
||||
},
|
||||
"unixMicro": builtinFunc{
|
||||
"unixMicro",
|
||||
func(a ...any) (any, ArErr) {
|
||||
return newNumber().SetInt64(N.UnixMicro()), ArErr{}
|
||||
},
|
||||
},
|
||||
"format": builtinFunc{
|
||||
"date",
|
||||
func(a ...any) (any, ArErr) {
|
||||
if len(a) == 0 {
|
||||
return N.Format(time.UnixDate), ArErr{}
|
||||
}
|
||||
return N.Format(a[0].(string)), ArErr{}
|
||||
},
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
||||
var ArTime = map[any]any{
|
||||
"snooze": builtinFunc{"snooze", func(a ...any) (any, ArErr) {
|
||||
if len(a) > 0 {
|
||||
float, _ := a[0].(number).Float64()
|
||||
time.Sleep(time.Duration(float*1000000000) * time.Nanosecond)
|
||||
}
|
||||
return nil, ArErr{}
|
||||
}},
|
||||
"now": builtinFunc{"now", func(a ...any) (any, ArErr) {
|
||||
return ArTimeClass(time.Now()), ArErr{}
|
||||
}},
|
||||
"parse": builtinFunc{"parse", func(a ...any) (any, ArErr) {
|
||||
if len(a) == 1 {
|
||||
N, err := time.Parse(time.UnixDate, a[0].(string))
|
||||
if err != nil {
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: err.Error(),
|
||||
}
|
||||
}
|
||||
return ArTimeClass(N), ArErr{}
|
||||
} else if len(a) > 1 {
|
||||
N, err := time.Parse(a[0].(string), a[1].(string))
|
||||
if err != nil {
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: err.Error(),
|
||||
EXISTS: true,
|
||||
}
|
||||
}
|
||||
return ArTimeClass(N), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: "parse requires 2 arguments",
|
||||
EXISTS: true,
|
||||
}
|
||||
}},
|
||||
"parseInLocation": builtinFunc{"parseInLocation", func(a ...any) (any, ArErr) {
|
||||
if len(a) > 2 {
|
||||
N, err := time.ParseInLocation(a[0].(string), a[1].(string), time.Local)
|
||||
if err != nil {
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: err.Error(),
|
||||
EXISTS: true,
|
||||
}
|
||||
}
|
||||
return ArTimeClass(N), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: "parseInLocation requires 3 arguments",
|
||||
EXISTS: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
"date": builtinFunc{"date", func(a ...any) (any, ArErr) {
|
||||
if len(a) > 0 {
|
||||
N, err := time.Parse(time.UnixDate, a[0].(string))
|
||||
if err != nil {
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: err.Error(),
|
||||
EXISTS: true,
|
||||
}
|
||||
}
|
||||
return ArTimeClass(N), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: "date requires 1 argument",
|
||||
EXISTS: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
"Unix": builtinFunc{"Unix", func(a ...any) (any, ArErr) {
|
||||
if len(a) > 1 {
|
||||
sec, _ := a[0].(number).Float64()
|
||||
nsec, _ := a[1].(number).Float64()
|
||||
return ArTimeClass(time.Unix(int64(sec), int64(nsec))), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: "Unix requires 2 arguments",
|
||||
EXISTS: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
"UnixMilli": builtinFunc{"UnixMilli", func(a ...any) (any, ArErr) {
|
||||
if len(a) > 0 {
|
||||
msec, _ := a[0].(number).Float64()
|
||||
return ArTimeClass(time.UnixMilli(int64(msec))), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: "UnixMilli requires 1 argument",
|
||||
EXISTS: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
"UnixMicro": builtinFunc{"UnixMicro", func(a ...any) (any, ArErr) {
|
||||
if len(a) > 0 {
|
||||
usec, _ := a[0].(number).Float64()
|
||||
return ArTimeClass(time.UnixMicro(int64(usec))), ArErr{}
|
||||
}
|
||||
return nil, ArErr{
|
||||
TYPE: "ArErr",
|
||||
message: "UnixMicro requires 1 argument",
|
||||
EXISTS: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func anyToArgon(x any, quote bool) string {
|
||||
@@ -22,8 +23,31 @@ func anyToArgon(x any, quote bool) string {
|
||||
} else if math.IsInf(num, -1) {
|
||||
return "-infinity"
|
||||
} else {
|
||||
return strconv.FormatFloat(num, 'f', -1, 64)
|
||||
return numberToString(x, 0)
|
||||
}
|
||||
case bool:
|
||||
return strconv.FormatBool(x)
|
||||
case nil:
|
||||
return "null"
|
||||
case ArMap:
|
||||
keys := make([]any, len(x))
|
||||
|
||||
i := 0
|
||||
for k := range x {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
output := []string{}
|
||||
for _, key := range keys {
|
||||
output = append(output, anyToArgon(key, true)+": "+anyToArgon(x[key], true))
|
||||
}
|
||||
return "{" + strings.Join(output, ", ") + "}"
|
||||
case builtinFunc:
|
||||
return "<builtin function " + x.name + ">"
|
||||
case Callable:
|
||||
return "<function " + x.name + ">"
|
||||
case ArClass:
|
||||
return anyToArgon(x.value, false)
|
||||
default:
|
||||
return fmt.Sprint(x)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ type UNPARSEcode struct {
|
||||
path string
|
||||
}
|
||||
|
||||
// returns (translateNumber | translateString| nil), success, error
|
||||
// returns (translateNumber | translateString| nil), success, error, step
|
||||
func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine bool) (any, bool, ArErr, int) {
|
||||
if isLine {
|
||||
if isBlank(code) {
|
||||
@@ -19,14 +19,20 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b
|
||||
}
|
||||
}
|
||||
}
|
||||
if isCall(code) {
|
||||
if isSetVariable(code) {
|
||||
return parseSetVariable(code, index, codelines)
|
||||
} else if isBrackets(code) {
|
||||
return parseBrackets(code, index, codelines)
|
||||
} else if isNumber(code) {
|
||||
return parseNumber(code)
|
||||
} else if isNegative(code) {
|
||||
return parseNegative(code, index, codelines)
|
||||
} else if isCall(code) {
|
||||
return parseCall(code, index, codelines)
|
||||
} else if isVariable(code) {
|
||||
return parseVariable(code)
|
||||
} else if isMapGet(code) {
|
||||
return mapGetParse(code, index, codelines)
|
||||
} else if isNumber(code) {
|
||||
return parseNumber(code)
|
||||
} else if isString(code) {
|
||||
return parseString(code)
|
||||
}
|
||||
@@ -36,9 +42,9 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b
|
||||
// returns [](translateNumber | translateString), error
|
||||
func translate(codelines []UNPARSEcode) ([]any, ArErr) {
|
||||
translated := []any{}
|
||||
for i, code := range codelines {
|
||||
val, _, err, _ := translateVal(code, i, codelines, true)
|
||||
|
||||
for i := 0; i < len(codelines); {
|
||||
val, _, err, step := translateVal(codelines[i], i, codelines, true)
|
||||
i += step
|
||||
if err.EXISTS {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ func typeof(val any) string {
|
||||
return "function"
|
||||
case builtinFunc:
|
||||
return "function"
|
||||
case ArMap:
|
||||
return "map"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var variableCompile = makeRegex(`([a-zA-Z_])([a-zA-Z0-9_])*`)
|
||||
var variableCompile = makeRegex(`( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`)
|
||||
var setVariableCompile = makeRegex(`( *)(let( +))?([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*(\(( *)((([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)(( *)\,( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)*)?( *)\))?( *)=(.|\n)+`)
|
||||
|
||||
var blockedVariableNames = map[string]bool{
|
||||
"if": true,
|
||||
@@ -21,12 +22,6 @@ var blockedVariableNames = map[string]bool{
|
||||
"do": true,
|
||||
}
|
||||
|
||||
type variableValue struct {
|
||||
VAL any
|
||||
EXISTS any
|
||||
origin string
|
||||
}
|
||||
|
||||
type accessVariable struct {
|
||||
name string
|
||||
line int
|
||||
@@ -34,6 +29,17 @@ type accessVariable struct {
|
||||
path string
|
||||
}
|
||||
|
||||
type setVariable struct {
|
||||
TYPE string
|
||||
name string
|
||||
value any
|
||||
function bool
|
||||
params []string
|
||||
line int
|
||||
code string
|
||||
path string
|
||||
}
|
||||
|
||||
func isVariable(code UNPARSEcode) bool {
|
||||
return variableCompile.MatchString(code.code)
|
||||
}
|
||||
@@ -49,8 +55,71 @@ func parseVariable(code UNPARSEcode) (accessVariable, bool, ArErr, int) {
|
||||
func readVariable(v accessVariable, stack stack) (any, ArErr) {
|
||||
for i := len(stack) - 1; i >= 0; i-- {
|
||||
if val, ok := stack[i][v.name]; ok {
|
||||
return val.VAL, ArErr{}
|
||||
return val, ArErr{}
|
||||
}
|
||||
}
|
||||
return nil, ArErr{"Runtime Error", "variable \"" + v.name + "\" does not exist", v.line, v.path, v.code, true}
|
||||
}
|
||||
|
||||
func isSetVariable(code UNPARSEcode) bool {
|
||||
return setVariableCompile.MatchString(code.code)
|
||||
}
|
||||
|
||||
func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVariable, bool, ArErr, int) {
|
||||
trim := strings.TrimSpace(code.code)
|
||||
equalsplit := strings.SplitN(trim, "=", 2)
|
||||
spacesplit := strings.SplitN(equalsplit[0], " ", 2)
|
||||
TYPE := "auto"
|
||||
name := strings.TrimSpace(equalsplit[0])
|
||||
params := []string{}
|
||||
function := false
|
||||
if spacesplit[0] == "let" {
|
||||
TYPE = "let"
|
||||
name = strings.TrimSpace(spacesplit[1])
|
||||
}
|
||||
if name[len(name)-1] == ')' {
|
||||
function = true
|
||||
bracketsplit := strings.SplitN(name, "(", 2)
|
||||
name = bracketsplit[0]
|
||||
params = strings.Split(bracketsplit[1][:len(bracketsplit[1])-1], ",")
|
||||
for i := 0; i < len(params); i++ {
|
||||
params[i] = strings.TrimSpace(params[i])
|
||||
}
|
||||
}
|
||||
if blockedVariableNames[name] {
|
||||
return setVariable{}, false, ArErr{"Naming Error", "Naming Error: \"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1
|
||||
}
|
||||
value, success, err, i := translateVal(UNPARSEcode{code: equalsplit[1], realcode: code.realcode, line: code.line, path: code.path}, index, lines, true)
|
||||
if !success {
|
||||
return setVariable{}, false, err, i
|
||||
}
|
||||
return setVariable{TYPE: TYPE, name: name, value: value, function: function, params: params, line: code.line, code: code.code, path: code.path}, true, ArErr{}, i
|
||||
}
|
||||
|
||||
func setVariableValue(v setVariable, stack stack) (any, ArErr) {
|
||||
var resp any
|
||||
if v.function {
|
||||
resp = Callable{v.name, v.params, v.value, v.code, stack, v.line}
|
||||
} else {
|
||||
respp, err := runVal(v.value, stack)
|
||||
if err.EXISTS {
|
||||
return nil, err
|
||||
}
|
||||
resp = respp
|
||||
}
|
||||
if v.TYPE == "let" {
|
||||
if _, ok := stack[len(stack)-1][v.name]; ok {
|
||||
return stack, ArErr{"Runtime Error", "variable \"" + v.name + "\" already exists", v.line, v.path, v.code, true}
|
||||
}
|
||||
stack[len(stack)-1][v.name] = resp
|
||||
} else {
|
||||
for i := len(stack) - 1; i >= 0; i-- {
|
||||
if _, ok := stack[i][v.name]; ok {
|
||||
stack[i][v.name] = resp
|
||||
return stack, ArErr{}
|
||||
}
|
||||
}
|
||||
stack[len(stack)-1][v.name] = resp
|
||||
}
|
||||
return resp, ArErr{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user