From f0620354c07b92077dc8bf22f16db91537e4a9cd Mon Sep 17 00:00:00 2001 From: William Bell Date: Sun, 26 Feb 2023 01:33:02 +0000 Subject: [PATCH] start adding maps --- build.sh => build | 0 run | 2 ++ src/built-in-functions.go | 17 +++++++++- src/built-ins.go | 12 +++++++ src/call.go | 9 +++--- src/callable.go | 2 +- src/import.go | 2 +- src/main.go | 2 ++ src/map.go | 68 +++++++++++++++++++++++++++++++++++++++ src/run.go | 6 ++-- src/translate.go | 2 ++ src/variable.go | 2 +- test.ar | 4 ++- 13 files changed, 117 insertions(+), 11 deletions(-) rename build.sh => build (100%) mode change 100644 => 100755 create mode 100755 run create mode 100644 src/map.go diff --git a/build.sh b/build old mode 100644 new mode 100755 similarity index 100% rename from build.sh rename to build diff --git a/run b/run new file mode 100755 index 0000000..0994fe7 --- /dev/null +++ b/run @@ -0,0 +1,2 @@ +# run the go run command passing the path to the main.go file, with the working directory set to the bin folder. pass in the arguments +go run ./src $@ \ No newline at end of file diff --git a/src/built-in-functions.go b/src/built-in-functions.go index 40ca7b9..ae96948 100644 --- a/src/built-in-functions.go +++ b/src/built-in-functions.go @@ -1,6 +1,9 @@ package main -import "fmt" +import ( + "fmt" + "time" +) type builtinFunc struct { name string @@ -32,3 +35,15 @@ func ArgonMult(args ...any) (any, ArErr) { return newNumber().Mul(y.(number), x.(number)) }, args), ArErr{} } + +func ArgonSleep(args ...any) (any, ArErr) { + if len(args) > 0 { + float, _ := args[0].(number).Float64() + time.Sleep(time.Duration(float*1000000000) * time.Nanosecond) + } + return nil, ArErr{} +} + +func ArgonTimestamp(args ...any) (any, ArErr) { + return newNumber().Quo(newNumber().SetInt64(time.Now().UnixNano()), newNumber().SetInt64(1000000000)), ArErr{} +} diff --git a/src/built-ins.go b/src/built-ins.go index d250468..d904c33 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -15,10 +15,22 @@ func init() { 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}}, + } pi, _ := newNumber().SetString("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989") vars["PI"] = variableValue{ EXISTS: true, diff --git a/src/call.go b/src/call.go index 7859baf..bfe4bec 100644 --- a/src/call.go +++ b/src/call.go @@ -11,6 +11,7 @@ type call struct { args []any code string line int + path string } func isCall(code UNPARSEcode) bool { @@ -50,10 +51,10 @@ func parseCall(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, if !works { return nil, false, ArErr{"Syntax Error", "invalid call", code.line, code.path, code.realcode, true}, 1 } - return call{callable: callable, args: arguments, line: code.line, code: code.code}, true, ArErr{}, 1 + return call{callable: callable, args: arguments, line: code.line, code: code.realcode, path: code.path}, true, ArErr{}, 1 } -func runCall(c call, stack []map[string]variableValue) (any, ArErr) { +func runCall(c call, stack stack) (any, ArErr) { callable, err := runVal(c.callable, stack) if err.EXISTS { return nil, err @@ -70,7 +71,7 @@ func runCall(c call, stack []map[string]variableValue) (any, ArErr) { case builtinFunc: return x.FUNC(args...) case Callable: - return nil, ArErr{"Runtime Error", "cannot call a class", c.line, "", c.code, true} + return nil, ArErr{"Runtime Error", "cannot call a class", c.line, c.path, c.code, true} } - return nil, ArErr{"Runtime Error", typeof(callable) + "' is not callable", c.line, "", c.code, true} + return nil, ArErr{"Runtime Error", "type '" + typeof(callable) + "' is not callable", c.line, c.path, c.code, true} } diff --git a/src/callable.go b/src/callable.go index ee03c02..fbee1d9 100644 --- a/src/callable.go +++ b/src/callable.go @@ -4,6 +4,6 @@ type Callable struct { name string params []string code []any - stack []map[string]variableValue + stack stack line int } diff --git a/src/import.go b/src/import.go index 667d9ad..709a0a1 100644 --- a/src/import.go +++ b/src/import.go @@ -98,7 +98,7 @@ func importMod(realpath string, origin string, main bool) ArErr { if translationerr.EXISTS { return translationerr } - _, runimeErr := run(translated, []map[string]variableValue{vars}) + _, runimeErr := run(translated, stack{vars}) if runimeErr.EXISTS { return runimeErr } diff --git a/src/main.go b/src/main.go index 35f25ee..7f8765b 100644 --- a/src/main.go +++ b/src/main.go @@ -7,6 +7,8 @@ import ( // args without the program path var Args = os.Args[1:] +type stack = []map[string]variableValue + func main() { ex, e := os.Getwd() if e != nil { diff --git a/src/map.go b/src/map.go new file mode 100644 index 0000000..914a2dc --- /dev/null +++ b/src/map.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "strings" +) + +type ArMap = map[any]any + +var mapGetCompile = makeRegex(".+\\.([a-zA-Z_])([a-zA-Z0-9_])*( *)") + +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{} + } + return nil, ArErr{ + "TypeError", + "cannot read " + anyToArgon(key, true) + " from type '" + typeof(resp) + "'", + r.line, + r.path, + r.code, + true, + } +} + +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 := translateString{key, code.realcode, code.line} + return ArMapGet{resp, k, code.line, code.realcode, code.path}, true, ArErr{}, 1 +} diff --git a/src/run.go b/src/run.go index 86bf613..dc2b62a 100644 --- a/src/run.go +++ b/src/run.go @@ -1,7 +1,7 @@ package main // returns (number|string|nil), error -func runVal(line any, stack []map[string]variableValue) (any, ArErr) { +func runVal(line any, stack stack) (any, ArErr) { switch x := line.(type) { case translateNumber: return (x.number), ArErr{} @@ -11,12 +11,14 @@ func runVal(line any, stack []map[string]variableValue) (any, ArErr) { return runCall(x, stack) case accessVariable: return readVariable(x, stack) + case ArMapGet: + return mapGet(x, stack) } panic("unreachable") } // returns error -func run(translated []any, stack []map[string]variableValue) (any, ArErr) { +func run(translated []any, stack stack) (any, ArErr) { for _, val := range translated { _, err := runVal(val, stack) if err.EXISTS { diff --git a/src/translate.go b/src/translate.go index ecda5d4..4b91321 100644 --- a/src/translate.go +++ b/src/translate.go @@ -23,6 +23,8 @@ func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine b 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) { diff --git a/src/variable.go b/src/variable.go index 37c6901..33ff63c 100644 --- a/src/variable.go +++ b/src/variable.go @@ -46,7 +46,7 @@ func parseVariable(code UNPARSEcode) (accessVariable, bool, ArErr, int) { return accessVariable{name: name, code: code.code, line: code.line}, true, ArErr{}, 1 } -func readVariable(v accessVariable, stack []map[string]variableValue) (any, ArErr) { +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{} diff --git a/test.ar b/test.ar index d9314ed..cf013f8 100644 --- a/test.ar +++ b/test.ar @@ -1 +1,3 @@ -log(mult(PI,PI, 2,4,34,5465)) \ No newline at end of file +log(time.now()) +time.snooze(1) +log(time.now()) \ No newline at end of file