work on adding indexing and slices

This commit is contained in:
2023-03-10 00:19:03 +00:00
parent cd1027630c
commit fe05d818de
12 changed files with 616 additions and 134 deletions

View File

@@ -8,7 +8,6 @@
ARGON 3 is a math-driven programming language designed to make code easy to read and write. It's not meant to be fast, as it's interpreted. This specification should be used as a guideline, and is subject to change for later versions. Later updates for Argon 3 should be backwards compatible (where possible) with code designed for older versions of the interpreter.
## 📚 Features
- Easy to read and write: Argon 3 is designed with clarity of code in mind, making it easier for you and others to read and write code.
- All numbers are stored as rational numbers, preventing precision errors.
- Math-driven: Designed for mathematical computations, Argon 3 uses techniques and rules set in maths. It's designed to be easy for mathematicians to write and understand algorithms in.
@@ -20,7 +19,6 @@ ARGON 3 is a math-driven programming language designed to make code easy to read
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
To use Argon 3, you can create a file with the .ar extension and write your code in it. Then, you can run your code using the interpreter. For example, if you have a file called example.ar, you can run it using the following command:
```

View File

@@ -3,7 +3,7 @@ package main
var vars = scope{}
func init() {
vars["vars"] = vars
vars["global"] = vars
vars["term"] = ArTerm
vars["true"] = true
vars["false"] = false
@@ -21,10 +21,33 @@ func init() {
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot get length of " + typeof(a[0]), EXISTS: true}
}}
vars["map"] = builtinFunc{"map", func(a ...any) (any, ArErr) {
if len(a) == 0 {
return ArMap{}, ArErr{}
}
switch x := a[0].(type) {
case ArMap:
return x, ArErr{}
case string:
newmap := ArMap{}
for i, v := range x {
newmap[i] = string(v)
}
return newmap, ArErr{}
case []any:
newmap := ArMap{}
for i, v := range x {
newmap[i] = v
}
return newmap, ArErr{}
}
return nil, ArErr{TYPE: "TypeError", message: "Cannot create map from " + typeof(a[0]), EXISTS: true}
}}
vars["time"] = ArTime
vars["PI"] = PI
vars["π"] = PI
vars["e"] = e
sqrt := builtinFunc{"sqrt", ArgonSqrt}
vars["sqrt"] = sqrt
vars["thread"] = builtinFunc{"thread", ArThread}
}

View File

@@ -30,7 +30,7 @@ func parseCall(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool,
for i := 1; i < len(splitby); i++ {
name := strings.Join(splitby[0:i], "(")
argstr := strings.Join(splitby[i:], "(")
args, success, argserr := getValuesFromCommas(argstr, index, codelines)
args, success, argserr := getValuesFromLetter(argstr, ",", index, codelines, true)
arguments = args
if !success {
if i == len(splitby)-1 {
@@ -56,9 +56,18 @@ func parseCall(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool,
}
func runCall(c call, stack stack) (any, ArErr) {
callable, err := runVal(c.callable, stack)
if err.EXISTS {
return nil, err
var callable any
switch x := c.callable.(type) {
case builtinFunc:
callable = x
case Callable:
callable = x
default:
callable_, err := runVal(c.callable, stack)
if err.EXISTS {
return nil, err
}
callable = callable_
}
args := []any{}
level := append(stack, scope{})

View File

@@ -1,27 +0,0 @@
package main
import (
"strings"
)
func getValuesFromCommas(str string, index int, codelines []UNPARSEcode) ([]any, bool, ArErr) {
// make a function which takes a string of code and returns a translated values
str = strings.Trim(str, " ")
commasplit := strings.Split(str, ",")
temp := []string{}
arguments := []any{}
if str != "" {
for i, arg := range commasplit {
temp = append(temp, arg)
test := strings.TrimSpace(strings.Join(temp, ","))
resp, worked, _, _ := translateVal(UNPARSEcode{code: test, realcode: codelines[index].realcode, line: index + 1, path: codelines[index].path}, index, codelines, false)
if worked {
arguments = append(arguments, resp)
temp = []string{}
} else if i == len(commasplit)-1 {
return nil, false, ArErr{"Syntax Error", "invalid argument", codelines[index].line, codelines[index].path, codelines[index].realcode, true}
}
}
}
return arguments, true, ArErr{}
}

View File

@@ -0,0 +1,32 @@
package main
import (
"strings"
)
func getValuesFromLetter(str string, splitstr string, index int, codelines []UNPARSEcode, allowempty bool) ([]any, bool, ArErr) {
// make a function which takes a string of code and returns a translated values
str = strings.Trim(str, " ")
commasplit := strings.Split(str, splitstr)
temp := []string{}
arguments := []any{}
if str != "" {
for i, arg := range commasplit {
temp = append(temp, arg)
test := strings.TrimSpace(strings.Join(temp, splitstr))
if test == "" && allowempty {
arguments = append(arguments, nil)
temp = []string{}
} else {
resp, worked, _, _ := translateVal(UNPARSEcode{code: test, realcode: codelines[index].realcode, line: index + 1, path: codelines[index].path}, index, codelines, false)
if worked {
arguments = append(arguments, resp)
temp = []string{}
} else if i == len(commasplit)-1 {
return nil, false, ArErr{"Syntax Error", "invalid argument", codelines[index].line, codelines[index].path, codelines[index].realcode, true}
}
}
}
}
return arguments, true, ArErr{}
}

View File

@@ -1,93 +0,0 @@
package main
import (
"fmt"
"strings"
)
type ArMap = map[any]any
type ArClass struct {
value any
MAP ArMap
}
var mapGetCompile = makeRegex(`(.|\n)+\.([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`)
type ArMapGet struct {
VAL any
key any
line int
code string
path string
}
func mapGet(r ArMapGet, stack stack) (any, ArErr) {
resp, err := runVal(r.VAL, stack)
if err.EXISTS {
return nil, err
}
key, err := runVal(r.key, stack)
if err.EXISTS {
return nil, err
}
switch m := resp.(type) {
case ArMap:
if _, ok := m[key]; !ok {
return nil, ArErr{
"KeyError",
"key '" + fmt.Sprint(key) + "' not found",
r.line,
r.path,
r.code,
true,
}
}
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",
"cannot read " + anyToArgon(key, true, true, 3, 0, false, 0) + " from type '" + typeof(resp) + "'",
r.line,
r.path,
r.code,
true,
}
}
func classVal(r any) any {
if _, ok := r.(ArClass); ok {
return r.(ArClass).value
}
return r
}
func isMapGet(code UNPARSEcode) bool {
return mapGetCompile.MatchString(code.code)
}
func mapGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapGet, bool, ArErr, int) {
trim := strings.TrimSpace(code.code)
split := strings.Split(trim, ".")
start := strings.Join(split[:len(split)-1], ".")
key := split[len(split)-1]
resp, worked, err, i := translateVal(UNPARSEcode{code: start, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, false)
if !worked {
return ArMapGet{}, false, err, i
}
k := key
return ArMapGet{resp, k, code.line, code.realcode, code.path}, true, ArErr{}, 1
}

477
src/mapAndArray.go Normal file
View File

@@ -0,0 +1,477 @@
package main
import (
"fmt"
"strings"
)
type ArMap = map[any]any
type ArArray = []any
type ArClass struct {
value any
MAP ArMap
}
var mapGetCompile = makeRegex(`(.|\n)+\.([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`)
var indexGetCompile = makeRegex(`(.|\n)+\[(.|\n)+\]( *)`)
type ArMapGet struct {
VAL any
start any
end any
step any
index bool
numberofindex int
line int
code string
path string
}
func mapGet(r ArMapGet, stack stack) (any, ArErr) {
resp, err := runVal(r.VAL, stack)
if err.EXISTS {
return nil, err
}
switch m := resp.(type) {
case ArMap:
if r.numberofindex > 1 {
return nil, ArErr{
"IndexError",
"index not found",
r.line,
r.path,
r.code,
true,
}
}
key, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
if _, ok := m[key]; !ok {
return nil, ArErr{
"KeyError",
"key '" + fmt.Sprint(key) + "' not found",
r.line,
r.path,
r.code,
true,
}
}
return m[key], ArErr{}
case ArArray:
startindex := 0
endindex := 1
step := 1
if !r.index {
key, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
if key == "length" {
return len(m), ArErr{}
}
}
if r.start != nil {
sindex, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
if typeof(sindex) != "number" {
return nil, ArErr{
"TypeError",
"index must be a number",
r.line,
r.path,
r.code,
true,
}
}
num := sindex.(number)
if !num.IsInt() {
return nil, ArErr{
"TypeError",
"index must be an integer",
r.line,
r.path,
r.code,
true,
}
}
startindex = int(num.Num().Int64())
endindex = startindex + 1
}
if r.end != nil {
eindex, err := runVal(r.end, stack)
if err.EXISTS {
return nil, err
}
if typeof(eindex) != "number" {
return nil, ArErr{
"TypeError",
"ending index must be a number",
r.line,
r.path,
r.code,
true,
}
}
num := eindex.(number)
if !num.IsInt() {
return nil, ArErr{
"TypeError",
"ending index must be an integer",
r.line,
r.path,
r.code,
true,
}
}
endindex = int(num.Num().Int64())
} else if r.numberofindex > 1 {
endindex = len(m)
}
if r.step != nil {
step, err := runVal(r.step, stack)
if err.EXISTS {
return nil, err
}
if typeof(step) != "number" {
return nil, ArErr{
"TypeError",
"step must be a number",
r.line,
r.path,
r.code,
true,
}
}
num := step.(number)
if !num.IsInt() {
return nil, ArErr{
"TypeError",
"step must be an integer",
r.line,
r.path,
r.code,
true,
}
}
step = int(num.Num().Int64())
}
if startindex < 0 {
startindex = len(m) + startindex
}
if endindex < 0 {
endindex = len(m) + endindex
}
if step < 0 {
step = -step
startindex, endindex = endindex, startindex
}
if startindex < 0 || startindex >= len(m) {
return nil, ArErr{
"IndexError",
"index '" + fmt.Sprint(startindex) + "' out of range",
r.line,
r.path,
r.code,
true,
}
}
if endindex < 0 || endindex > len(m) {
return nil, ArErr{
"IndexError",
"index '" + fmt.Sprint(endindex) + "' out of range",
r.line,
r.path,
r.code,
true,
}
}
if step == 0 {
return nil, ArErr{
"ValueError",
"step cannot be 0",
r.line,
r.path,
r.code,
true,
}
}
return m[startindex:endindex:step], ArErr{}
case ArClass:
if r.numberofindex > 1 {
return nil, ArErr{
"IndexError",
"index not found",
r.line,
r.path,
r.code,
true,
}
}
key, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
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{}
case string:
startindex := 0
endindex := 1
step := 1
if !r.index {
key, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
if key == "length" {
return len(m), ArErr{}
}
}
if r.start != nil {
sindex, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
if typeof(sindex) != "number" {
return nil, ArErr{
"TypeError",
"index must be a number",
r.line,
r.path,
r.code,
true,
}
}
num := sindex.(number)
if !num.IsInt() {
return nil, ArErr{
"TypeError",
"index must be an integer",
r.line,
r.path,
r.code,
true,
}
}
startindex = int(num.Num().Int64())
endindex = startindex + 1
}
if r.end != nil {
eindex, err := runVal(r.end, stack)
if err.EXISTS {
return nil, err
}
if typeof(eindex) != "number" {
return nil, ArErr{
"TypeError",
"ending index must be a number",
r.line,
r.path,
r.code,
true,
}
}
num := eindex.(number)
if !num.IsInt() {
return nil, ArErr{
"TypeError",
"ending index must be an integer",
r.line,
r.path,
r.code,
true,
}
}
endindex = int(num.Num().Int64())
} else if r.numberofindex > 1 {
endindex = len(m)
}
if r.step != nil {
step, err := runVal(r.step, stack)
if err.EXISTS {
return nil, err
}
if typeof(step) != "number" {
return nil, ArErr{
"TypeError",
"step must be a number",
r.line,
r.path,
r.code,
true,
}
}
num := step.(number)
if !num.IsInt() {
return nil, ArErr{
"TypeError",
"step must be an integer",
r.line,
r.path,
r.code,
true,
}
}
step = int(num.Num().Int64())
}
if startindex < 0 {
startindex = len(m) + startindex
}
if endindex < 0 {
endindex = len(m) + endindex
}
if step < 0 {
step = -step
startindex, endindex = endindex, startindex
}
if startindex < 0 || startindex >= len(m) {
return nil, ArErr{
"IndexError",
"index '" + fmt.Sprint(startindex) + "' out of range",
r.line,
r.path,
r.code,
true,
}
}
if endindex < 0 || endindex > len(m) {
return nil, ArErr{
"IndexError",
"index '" + fmt.Sprint(endindex) + "' out of range",
r.line,
r.path,
r.code,
true,
}
}
if step == 0 {
return nil, ArErr{
"ValueError",
"step cannot be 0",
r.line,
r.path,
r.code,
true,
}
}
return string(([]byte(m))[startindex:endindex:step]), ArErr{}
}
key, err := runVal(r.start, stack)
if err.EXISTS {
return nil, err
}
return nil, ArErr{
"TypeError",
"cannot read " + anyToArgon(key, true, true, 3, 0, false, 0) + " from type '" + typeof(resp) + "'",
r.line,
r.path,
r.code,
true,
}
}
func classVal(r any) any {
if _, ok := r.(ArClass); ok {
return r.(ArClass).value
}
return r
}
func isMapGet(code UNPARSEcode) bool {
return mapGetCompile.MatchString(code.code)
}
func mapGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapGet, bool, ArErr, int) {
trim := strings.TrimSpace(code.code)
split := strings.Split(trim, ".")
start := strings.Join(split[:len(split)-1], ".")
key := split[len(split)-1]
resp, worked, err, i := translateVal(UNPARSEcode{code: start, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, false)
if !worked {
return ArMapGet{}, false, err, i
}
k := key
return ArMapGet{resp, k, nil, nil, false, 1, code.line, code.realcode, code.path}, true, ArErr{}, 1
}
func isIndexGet(code UNPARSEcode) bool {
return indexGetCompile.MatchString(code.code)
}
func indexGetParse(code UNPARSEcode, index int, codelines []UNPARSEcode) (ArMapGet, bool, ArErr, int) {
trim := strings.TrimSpace(code.code)
trim = trim[:len(trim)-1]
split := strings.Split(trim, "[")
var toindex any
var start any
var end any
var step any
numberofindexs := 0
for i := 1; i < len(split); i++ {
ti := strings.Join(split[:i], "[")
innerbrackets := strings.Join(split[i:], "[")
args, success, argserr := getValuesFromLetter(innerbrackets, ":", index, codelines, true)
if !success {
if i == len(split)-1 {
return ArMapGet{}, false, argserr, 1
}
continue
}
if len(args) > 3 {
return ArMapGet{}, false, ArErr{
"SyntaxError",
"too many arguments for index get",
code.line,
code.path,
code.realcode,
true,
}, 1
}
tival, worked, err, i := translateVal(UNPARSEcode{code: ti, realcode: code.realcode, line: code.line, path: code.path}, index, codelines, false)
if !worked {
if i == len(split)-1 {
return ArMapGet{}, false, err, i
}
continue
}
numberofindexs = len(args)
if len(args) >= 1 {
toindex = tival
start = args[0]
}
if len(args) >= 2 {
end = args[1]
}
if len(args) >= 3 {
step = args[2]
}
}
if toindex == nil {
return ArMapGet{}, false, ArErr{
"SyntaxError",
"invalid index get",
code.line,
code.path,
code.realcode,
true,
}, 1
}
return ArMapGet{toindex, start, end, step, true, numberofindexs, code.line, code.realcode, code.path}, true, ArErr{}, 1
}

49
src/threading.go Normal file
View File

@@ -0,0 +1,49 @@
package main
import "sync"
func ArThread(args ...any) (any, ArErr) {
if len(args) == 0 {
return nil, ArErr{TYPE: "TypeError", message: "Cannot call thread without a function", EXISTS: true}
}
var tocall any
switch x := args[0].(type) {
case Callable:
tocall = x
case builtinFunc:
tocall = x
default:
return nil, ArErr{TYPE: "TypeError", message: "Cannot call thread with a '" + typeof(args[0]) + "'", EXISTS: true}
}
var resp any
var err ArErr
currentscope := stack{vars, scope{}}
hasrun := false
joined := false
var wg sync.WaitGroup
threaMap := ArMap{
"start": builtinFunc{"start", func(args ...any) (any, ArErr) {
if hasrun {
return nil, ArErr{TYPE: "Runtime Error", message: "Cannot start a thread twice", EXISTS: true}
}
hasrun = true
wg.Add(1)
go func() {
resp, err = runCall(call{tocall, []any{}, "", 0, ""}, currentscope)
wg.Done()
}()
return nil, ArErr{}
}},
"join": builtinFunc{"join", func(args ...any) (any, ArErr) {
if !hasrun {
return nil, ArErr{TYPE: "Runtime Error", message: "Cannot join a thread that has not started", EXISTS: true}
} else if joined {
return nil, ArErr{TYPE: "Runtime Error", message: "Cannot join a thread twice", EXISTS: true}
}
joined = true
wg.Wait()
return resp, err
}},
}
return threaMap, ArErr{}
}

View File

@@ -70,6 +70,9 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, color b
output = append(output, "\x1b[0m")
}
case ArMap:
if len(x) == 0 {
return "{}"
}
keys := make([]any, len(x))
i := 0

View File

@@ -61,6 +61,8 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b
return parseVariable(code)
} else if isMapGet(code) {
return mapGetParse(code, index, codelines)
} else if isIndexGet(code) {
return indexGetParse(code, index, codelines)
} else if isString(code) {
return parseString(code)
}

View File

@@ -5,7 +5,7 @@ import (
)
var variableCompile = makeRegex(`( *)([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*( *)`)
var validname = makeRegex(`(.|\n)+(\(( *)((([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}*))*)*)?( *)\))`)
var validname = makeRegex(`(.|\n)*(\(( *)((([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}*))*)*)?( *)\))`)
var setVariableCompile = makeRegex(`( *)(let( +))(.|\n)+( *)=(.|\n)+`)
var autoAsignVariableCompile = makeRegex(`(.|\n)+=(.|\n)+`)
var deleteVariableCompile = makeRegex(`( *)delete( +)(.|\n)+( *)`)
@@ -101,6 +101,9 @@ func nameToTranslated(code UNPARSEcode, index int, lines []UNPARSEcode) (any, bo
}
}
name := strings.TrimSpace(trimmed[:start])
if name == "" {
return setFunction{toset: nil, params: params}, true, ArErr{}, 1
}
if blockedVariableNames[name] {
return accessVariable{}, false, ArErr{"Naming Error", "\"" + name + "\" is a reserved keyword", code.line, code.path, code.realcode, true}, 1
}
@@ -136,6 +139,9 @@ func parseSetVariable(code UNPARSEcode, index int, lines []UNPARSEcode) (setVari
function = true
params = toset.(setFunction).params
toset = toset.(setFunction).toset
if toset == nil {
return setVariable{}, false, ArErr{"Type Error", "can't set for non variable, did you mean to put 'let' before?", code.line, code.path, code.realcode, true}, 1
}
default:
return setVariable{}, false, ArErr{"Type Error", "can't set for non variable, did you mean '=='?", code.line, code.path, code.realcode, true}, 1
}
@@ -210,7 +216,7 @@ func setVariableValue(v setVariable, stack stack) (any, ArErr) {
if err.EXISTS {
return nil, err
}
key, err := runVal(x.key, stack)
key, err := runVal(x.start, stack)
if err.EXISTS {
return nil, err
}
@@ -260,7 +266,7 @@ func runDelete(d ArDelete, stack stack) (any, ArErr) {
if err.EXISTS {
return nil, err
}
key, err := runVal(x.key, stack)
key, err := runVal(x.start, stack)
if err.EXISTS {
return nil, err
}

11
test.ar
View File

@@ -1,4 +1,7 @@
x = 10
term.log(x)
x = x+1
term.log(x)
let t = thread(f()=time.snooze(1))
term.log("start")
t.start()
term.log('started')
let val = t.join()
term.log('joined', val)