diff --git a/.gitignore b/.gitignore
index b7dab5e..9e87c05 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
node_modules
-build
\ No newline at end of file
+bin
\ No newline at end of file
diff --git a/build.bat b/build.bat
new file mode 100644
index 0000000..5d2dc11
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,3 @@
+@echo off
+
+go build -o bin/Argon-v3.exe ./src
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 9506b05..32ac8e8 100644
--- a/readme.md
+++ b/readme.md
@@ -1,11 +1,48 @@
-# Argon
+
+
+
+
+
Argon 3
+
-The go to language for mathematicians!
+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.
-# Read Me
+## 📚 Features
-due to the project being in very early stages, the readme docs file is not yet being worked on. [read the specification to get an understanding of how the language will work.](spec.md)
+ - 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.
+ - 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.
+ - Interpreted: Argon 3 is an interpreted language, so you don't need to compile your code before running it.
+ - Cross-platform: Argon 3 can be run on any platform that has an interpreter for it.
+ - Lightweight: The Argon 3 interpreter is small and doesn't require a lot of system resources to run.
-# Licence
+## 💻 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)`.
+
+## 📖 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:
+
+```
+argon example.ar
+```
+
+## 🔍 Specification
+
+For a detailed specification of the Argon 3 language, please refer to [spec.md](spec.md).
+
+## 🚀 Example Code
+
+Here's an example of how to define a function in Argon 3:
+
+```javascript
+f(x) = x^2 + 2*x + 1
+log('f(10) =', f(10))
+```
+
+This code defines a function f(x) that calculates x^2 + 2*x + 1. It then calls the function with an argument of 10 and logs the result to the console.
+
+Please note that this example is subject to change as the specification is in beta and may be updated frequently.
+
+## Licence
MIT
diff --git a/run.bat b/run.bat
new file mode 100644
index 0000000..bbe3f9c
--- /dev/null
+++ b/run.bat
@@ -0,0 +1,5 @@
+@echo off
+
+:: 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/spec.md b/spec.md
index 53581b7..6c501d6 100644
--- a/spec.md
+++ b/spec.md
@@ -24,10 +24,10 @@ reused variables, and infomation for use in understanding the pseudo REGEX:
## set variable
-`(let/const or nothing) {NAME} = {ANY}`
+`(let or nothing) {NAME} = {ANY}`
-let and const variables will set variables. if a const is already set in that stack, it will throw an error.
-at the end of a opperation (e.g. if, while, or function) drop the variable stack.
+let variables will set variables. at the end of a opperation (e.g. if, while, or function) drop the
+variable stack.
having no verb at the start suggests the program would like to edit a variables from a different stack.
if there is no variable found in the other stacks, then it sets one in the current stack as a let.
@@ -36,17 +36,16 @@ setting variables returns the value, which can be used.
example:
-```
-if (x = 10) > 5 [
+```javascript
+if (x = 10) > 5 do
log(x, 'is bigger than 5')
-]
```
---
## functions
-`(let/const or nothing) {NAME}({PARAMS}) = {CODE}`
+`(let or nothing) {NAME}({PARAMS}) = {CODE}`
the starting verb follows the rules set by [set variable](#set-variable).
@@ -54,41 +53,41 @@ function can be called by using its name followed by brackets with the params.
example:
-```
-
-const f(x) = x^2 + 2*x + 1
+```javascript
+f(x) = x^2 + 2*x + 1
log('f(10) =', f(10))
-
```
output:
-```
-
+```javascript
f(10) = 121
-
```
-if the function does not return, then the value given is unknown/null
+if the function does not return, then the value returned is `unknown`
---
## wrap
-`[{CODE}]`
+```
+do
+ {CODE}
+```
-a wrap encloses code in square brackets. its used to create a new scope, so variables set from
+a wrap encloses code indented in after the word `do` its used to create a new scope, so variables set from
inside the wraps scope are deleted once the wrap is finished.
example:
-```
+```javascript
let name = unknown
-[
+
+do
name = input('name: ')
let age = input('age: ')
log('you are', age, 'years old!')
-]
+
log('hello', name)
log('we do not know your age anymore because it got deleted when the wrap finished.')
```
@@ -97,17 +96,19 @@ A wrap, unless specificifed otherwise, can have a return value. This value can b
example:
-```
-const password = [
+```javascript
+let password = do
let password = input("set password: ")
- while len(password) < 8 [
+ while len(password) < 8 do
log("password must be longer then 8 characters!")
password = input("set password: ")
- ]
return password
-]
log("your password is", password)
```
If the wrap does not take a return value, then the wrap passes the return value back to a parent wrap.
+
+## Comments
+`//{COMMENT}`
+Comments allow the programmer to write a message into their code, without the message being processed by the computer.
\ No newline at end of file
diff --git a/src/comment.go b/src/comment.go
new file mode 100644
index 0000000..1e6fcd7
--- /dev/null
+++ b/src/comment.go
@@ -0,0 +1,7 @@
+package main
+
+var commentCompile = makeRegex("( *)//.*")
+
+func isComment(code UNPARSEcode) bool {
+ return commentCompile.MatchString(code.code)
+}
diff --git a/src/import.go b/src/import.go
new file mode 100644
index 0000000..35dc7c5
--- /dev/null
+++ b/src/import.go
@@ -0,0 +1,102 @@
+package main
+
+import (
+ "bufio"
+ "errors"
+ "log"
+ "os"
+ "path/filepath"
+)
+
+func FileExists(filename string) bool {
+ if _, err := os.Stat(filename); err == nil {
+ return true
+
+ } else if errors.Is(err, os.ErrNotExist) {
+ return false
+ } else {
+ return false
+ }
+}
+
+func readFile(path string) []UNPARSEcode {
+ file, err := os.Open(path)
+ if err != nil {
+ log.Fatal(err)
+ return nil
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ // optionally, resize scanner's capacity for lines over 64K, see next example
+ output := []UNPARSEcode{}
+ line := 1
+ for scanner.Scan() {
+ output = append(output, UNPARSEcode{scanner.Text(), line})
+ line++
+ }
+
+ if err := scanner.Err(); err != nil {
+ log.Fatal(err)
+ return nil
+ }
+ return output
+}
+
+func importMod(realpath string, origin string, main bool) string {
+ extention := filepath.Ext(realpath)
+ path := realpath
+ if extention == "" {
+ path += ".ar"
+ }
+ ex, err := os.Getwd()
+ if err != nil {
+ return err.Error()
+ }
+ executable, err := os.Executable()
+ if err != nil {
+ return err.Error()
+ }
+ executable = filepath.Dir(executable)
+ isABS := filepath.IsAbs(path)
+ var pathsToTest []string
+ if isABS {
+ pathsToTest = []string{
+ filepath.Join(path),
+ filepath.Join(realpath, "init.ar"),
+ }
+ } else {
+ pathsToTest = []string{
+ filepath.Join(origin, realpath, "init.ar"),
+ filepath.Join(origin, path),
+ filepath.Join(origin, "modules", path),
+ filepath.Join(origin, "modules", realpath, "init.ar"),
+ filepath.Join(ex, path),
+ filepath.Join(ex, "modules", realpath, "init.ar"),
+ filepath.Join(ex, "modules", path),
+ filepath.Join(executable, "modules", realpath, "init.ar"),
+ filepath.Join(executable, "modules", path),
+ }
+ }
+
+ var p string
+ var found bool
+ for _, p = range pathsToTest {
+ if FileExists(p) {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ return "File does not exist: " + realpath
+ }
+ codelines := readFile(p)
+
+ translated, translationerr := translate(codelines)
+ if translationerr != "" {
+ return translationerr
+ }
+ run(translated)
+ return ""
+}
diff --git a/src/main.go b/src/main.go
index 1b8c3d8..7ab9269 100644
--- a/src/main.go
+++ b/src/main.go
@@ -1,8 +1,23 @@
package main
-import "fmt"
+import (
+ "os"
+)
+
+// args without the program path
+var Args = os.Args[1:]
func main() {
- translate("")
- fmt.Println("hello world")
+
+ ex, e := os.Getwd()
+ if e != nil {
+ panic(e)
+ }
+ if len(Args) == 0 {
+ panic("No file specified")
+ }
+ err := importMod(Args[0], ex, true)
+ if err != "" {
+ panic(err)
+ }
}
diff --git a/src/number.go b/src/number.go
index a932068..044a163 100644
--- a/src/number.go
+++ b/src/number.go
@@ -6,6 +6,8 @@ import (
"strings"
)
+var numberCompile = makeRegex("( *)((\\-)?(([0-9]*(\\.[0-9]+)?)(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)|(0b[10]+(.[10]+)?(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)|(0x[a-fA-F0-9]+(.[a-fA-F0-9]+)?)|(0o[0-7]+(.[0-7]+)?(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?))( *)")
+
// a number type
type number = *big.Rat
@@ -19,6 +21,10 @@ func stringToNumber(str string) (*big.Rat, bool) {
return newNumber().SetString(str)
}
+func isNumber(code UNPARSEcode) bool {
+ return numberCompile.MatchString(code.code)
+}
+
// converts a number type to a string
func numberToString(num number, fraction int) string {
if fraction != 0 {
@@ -72,3 +78,12 @@ var subscript = map[byte]string{
'8': "₈",
'9': "₉",
}
+
+// returns translateNumber, success, error
+func parseNumber(code UNPARSEcode) (translateNumber, bool, string) {
+ output, _ := newNumber().SetString(code.code)
+ return translateNumber{
+ number: output,
+ line: code.line,
+ }, true, ""
+}
diff --git a/src/regex.go b/src/regex.go
new file mode 100644
index 0000000..1d47e72
--- /dev/null
+++ b/src/regex.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ "log"
+ "regexp"
+)
+
+func makeRegex(str string) *regexp.Regexp {
+ Compile, err := regexp.Compile("^(" + str + ")$")
+ if err != nil {
+ log.Fatal(err)
+ }
+ return Compile
+}
diff --git a/src/run.go b/src/run.go
new file mode 100644
index 0000000..c69bd42
--- /dev/null
+++ b/src/run.go
@@ -0,0 +1,24 @@
+package main
+
+import "fmt"
+
+func runLine(line any) (any, string) {
+ switch line.(type) {
+ case translateNumber:
+ return (numberToString(line.(translateNumber).number, 0)), ""
+ case translateString:
+ return (line.(translateString).str), ""
+ }
+ return nil, "Error: invalid code on line " + fmt.Sprint(line.(translateNumber).line) + ": " + line.(translateNumber).code
+}
+
+// returns error
+func run(translated []any) (any, string) {
+ for _, val := range translated {
+ _, err := runLine(val)
+ if err != "" {
+ return nil, err
+ }
+ }
+ return nil, ""
+}
diff --git a/src/string.go b/src/string.go
new file mode 100644
index 0000000..87bd260
--- /dev/null
+++ b/src/string.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+var stringCompile = makeRegex("(( *)\"((\\\\([a-z\\\"'`]))|[^\\\"])*\"( *))|(( *)'((\\\\([a-z\\'\"`]))|[^\\'])*'( *))")
+
+func isString(code UNPARSEcode) bool {
+ return stringCompile.MatchString(code.code)
+}
+
+func unquoted(
+ str string,
+) (string, error) {
+ str = strings.Trim(str, " ")
+ if str[0] == '\'' {
+ str = strings.Replace(str, "\\\"", "\"", -1)
+ str = strings.Replace(str, "\"", "\\\"", -1)
+ }
+ str = str[1 : len(str)-1]
+ str = strings.Replace(str, "\\'", "'", -1)
+ str = "\"" + str + "\""
+ return strconv.Unquote(str)
+}
+
+// returns translateString, success, error
+func parseString(code UNPARSEcode) (translateString, bool, string) {
+ trim := strings.Trim(code.code, " ")
+
+ unquoted, err := unquoted(trim)
+ if err != nil {
+ return translateString{}, false, "Syntax Error: invalid string on line " + fmt.Sprint(code.line) + ": " + code.code
+ }
+
+ return translateString{
+ str: unquoted,
+ line: code.line,
+ }, true, ""
+}
diff --git a/src/translate.go b/src/translate.go
index 5c4166e..88a356d 100644
--- a/src/translate.go
+++ b/src/translate.go
@@ -2,9 +2,42 @@ package main
import (
"fmt"
+ "log"
)
-func translate(code string) {
- output, _ := newNumber().SetString("3.1415")
- fmt.Println(numberToString(output, 0))
+// returns (translateNumber | translateString), success, error
+func translateVal(code UNPARSEcode, index int, codelines []UNPARSEcode, isLine bool) (any, bool, string) {
+ if isLine {
+ if isComment(code) {
+ return nil, true, ""
+ }
+ }
+
+ if isNumber(code) {
+ return parseNumber(code)
+ } else if isString(code) {
+ return parseString(code)
+ }
+ if isLine {
+ return nil, false, "Syntax Error: invalid code on line " + fmt.Sprint(code.line) + ": " + code.code
+ }
+ return nil, false, ""
+}
+
+// returns [](translateNumber | translateString), error
+func translate(codelines []UNPARSEcode) ([]any, string) {
+ translated := []any{}
+ for i, code := range codelines {
+ val, _, err := translateVal(code, i, codelines, true)
+
+ if err != "" {
+ log.Fatal(err)
+ return nil, err
+ }
+ if val == nil {
+ continue
+ }
+ translated = append(translated, val)
+ }
+ return translated, ""
}
diff --git a/src/types.go b/src/types.go
new file mode 100644
index 0000000..1ef3291
--- /dev/null
+++ b/src/types.go
@@ -0,0 +1,18 @@
+package main
+
+type UNPARSEcode struct {
+ code string
+ line int
+}
+
+type translateNumber struct {
+ number
+ code string
+ line int
+}
+
+type translateString struct {
+ str string
+ code string
+ line int
+}
diff --git a/test.ar b/test.ar
new file mode 100644
index 0000000..119aa6a
--- /dev/null
+++ b/test.ar
@@ -0,0 +1,26 @@
+0x1
+0x2
+0x3
+0x4
+0x5
+0x6
+0x7
+0x8
+0x9
+0xA
+0xB
+0xC
+0xD
+0xE
+0xF
+0x10
+0x11
+0x12
+0x13
+0x14
+0x15
+0x16
+0x17
+0x18
+0x19
+0x1A
\ No newline at end of file