add create functions

This commit is contained in:
2023-02-27 00:07:13 +00:00
parent f0620354c0
commit 1b3a4c44d9
23 changed files with 580 additions and 125 deletions

31
src/brackets.go Normal file
View 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
}

View File

@@ -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{}
}

View File

@@ -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}
}

View File

@@ -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}
}

View File

@@ -3,7 +3,8 @@ package main
type Callable struct {
name string
params []string
code []any
run any
code string
stack stack
line int
}

View File

@@ -4,7 +4,7 @@ import (
"strings"
)
var commentCompile = makeRegex(".*//.*")
var commentCompile = makeRegex("(.|\n)*//(.|\n)*")
func isComment(code UNPARSEcode) bool {
return commentCompile.MatchString(code.code)

View File

@@ -15,9 +15,11 @@ type ArErr struct {
}
func panicErr(err ArErr) {
fmt.Println(" File:", err.path+":"+fmt.Sprint(err.line))
fmt.Println(" " + err.code)
fmt.Println()
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)
}

View File

@@ -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
}

View File

@@ -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()

View File

@@ -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
View 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
}

View File

@@ -7,15 +7,15 @@ import (
)
type translateNumber struct {
number
code string
line int
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
}

View File

@@ -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")
}

View File

@@ -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
View 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,
}
},
},
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -14,6 +14,8 @@ func typeof(val any) string {
return "function"
case builtinFunc:
return "function"
case ArMap:
return "map"
}
return "unknown"
}

View File

@@ -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{}
}