mirror of
https://github.com/Open-Argon/argon-v3.git
synced 2025-12-06 00:46:07 +00:00
Start supporting numbers and strings
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
node_modules
|
||||
build
|
||||
bin
|
||||
47
readme.md
47
readme.md
@@ -1,11 +1,48 @@
|
||||
# Argon
|
||||
<div align="center">
|
||||
<p>
|
||||
<img width="80" src="https://raw.githubusercontent.com/Ugric/Argon/main/logo.png">
|
||||
</p>
|
||||
<h1>Argon 3</h1>
|
||||
</div>
|
||||
|
||||
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
|
||||
|
||||
5
run.bat
Normal file
5
run.bat
Normal file
@@ -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 %*
|
||||
51
spec.md
51
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.
|
||||
7
src/comment.go
Normal file
7
src/comment.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
var commentCompile = makeRegex("( *)//.*")
|
||||
|
||||
func isComment(code UNPARSEcode) bool {
|
||||
return commentCompile.MatchString(code.code)
|
||||
}
|
||||
102
src/import.go
Normal file
102
src/import.go
Normal file
@@ -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 ""
|
||||
}
|
||||
21
src/main.go
21
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, ""
|
||||
}
|
||||
|
||||
14
src/regex.go
Normal file
14
src/regex.go
Normal file
@@ -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
|
||||
}
|
||||
24
src/run.go
Normal file
24
src/run.go
Normal file
@@ -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, ""
|
||||
}
|
||||
42
src/string.go
Normal file
42
src/string.go
Normal file
@@ -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, ""
|
||||
}
|
||||
@@ -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, ""
|
||||
}
|
||||
|
||||
18
src/types.go
Normal file
18
src/types.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user