mirror of
https://github.com/Open-Argon/argon-v2.git
synced 2026-10-28 09:44:03 +00:00
540 lines
14 KiB
Go
540 lines
14 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var anyAndNewline = "((.)|(\\n))"
|
|
var variableOnly = "([a-zA-Z_])([a-zA-Z0-9_])*"
|
|
var stringCompile = makeRegex("(( *)\"((\\\\([a-z\\\"'`]))|[^\\\"])*\"( *))|(( *)'((\\\\([a-z\\'\"`]))|[^\\'])*'( *))|(( *)(`(\\\\[a-z\\\"'`\\n]|[^\\`])*`)( *))")
|
|
var numberCompile = makeRegex("( *)(\\-)?(([0-9]+(\\.[0-9]+)?)(e((\\-|\\+)?([0-9]+(\\.[0-9]+)?)))?)( *)")
|
|
var whileCompile = makeRegex("( *)(while( )+" + anyAndNewline + "+( )+\\[" + anyAndNewline + "*)( *)")
|
|
var subCompile = makeRegex("( *)(sub( )+" + variableOnly + "\\(" + anyAndNewline + "*\\)( )+\\[" + anyAndNewline + "*)( *)")
|
|
var ifCompile = makeRegex("( *)(if( )+" + anyAndNewline + "+( )+\\[" + anyAndNewline + "*)( *)")
|
|
var elseifCompile = makeRegex("( *)(\\] else if " + anyAndNewline + "+ \\[" + anyAndNewline + "*)( *)")
|
|
var openCompile = makeRegex("( *)(" + anyAndNewline + "+( )+\\[([^\\]])*)( *)")
|
|
var elseCompile = makeRegex("( *)\\] else \\[" + anyAndNewline + "*( *)")
|
|
var closeCompile = makeRegex("( *)\\]( *)")
|
|
var switchCloseCompile = makeRegex("( *)" + anyAndNewline + "*\\]" + anyAndNewline + "*\\[" + anyAndNewline + "*( *)")
|
|
var importCompile = makeRegex("( *)import " + anyAndNewline + "+( *)")
|
|
var bracketsCompile = makeRegex("( *)\\(" + anyAndNewline + "*\\)( *)")
|
|
var functionCompile = makeRegex("( *)" + variableOnly + "\\(" + anyAndNewline + "*\\)( *)")
|
|
var variableTextCompile = makeRegex("( *)" + variableOnly + "( *)")
|
|
var variableonlyCompile = makeRegex(variableOnly)
|
|
var setVariableCompile = makeRegex("( *)(((const|var) (" + variableOnly + "( *))=( *).+)|(( *)" + variableOnly + "( *))(( *)=( *).+))( *)")
|
|
var returnStatementCompile = makeRegex("( *)(return(( )+" + anyAndNewline + "*)?)( *)")
|
|
var itemsCompiled = makeRegex("( *)(\\[" + anyAndNewline + "*\\])( *)")
|
|
var breakStatementCompile = makeRegex("( *)break( *)")
|
|
var continueStatementCompile = makeRegex("( *)continue( *)")
|
|
var skipCompile = makeRegex("( *)(#(.*))?")
|
|
var processfunc func(codeseg code) (interface{}, bool)
|
|
var linefunc func(i int, codearray []code) (interface{}, int)
|
|
var opperators = [][]string{
|
|
{
|
|
"&&",
|
|
" and ",
|
|
}, {
|
|
"||",
|
|
" or ",
|
|
}, {
|
|
"!@",
|
|
" not in ",
|
|
" is not in ",
|
|
" isnt in ",
|
|
}, {
|
|
"@",
|
|
" in ",
|
|
" is in ",
|
|
}, {
|
|
"<=",
|
|
" is less than or equal to ",
|
|
" is smaller than or equal to ",
|
|
}, {
|
|
">=",
|
|
" is bigger than or equal to ",
|
|
" is more than or equal to ",
|
|
}, {
|
|
"<",
|
|
" is less than ",
|
|
" is smaller than ",
|
|
}, {
|
|
">",
|
|
" is bigger than ",
|
|
" is more than ",
|
|
}, {
|
|
"!=",
|
|
" is not ",
|
|
" is not equal to ",
|
|
" isnt equal to ",
|
|
" isnt ",
|
|
"!==",
|
|
}, {
|
|
"==",
|
|
" equals ",
|
|
" is equal to ",
|
|
" is ",
|
|
"===",
|
|
}, {
|
|
" plus ",
|
|
" add ",
|
|
"+",
|
|
}, {
|
|
" minus ",
|
|
" subtract ",
|
|
"-",
|
|
}, {
|
|
"*",
|
|
" x ",
|
|
" times ",
|
|
" multiplied by ",
|
|
}, {
|
|
" mod ",
|
|
" modulo ",
|
|
"%",
|
|
}, {
|
|
" div ",
|
|
" floor division of ",
|
|
" floor divistion ",
|
|
"//",
|
|
"$",
|
|
}, {
|
|
" over ",
|
|
" divided by ",
|
|
"/",
|
|
}, {
|
|
"!**",
|
|
"!^",
|
|
" root ",
|
|
"√",
|
|
}, {
|
|
" to the power of ",
|
|
"^",
|
|
"**",
|
|
}}
|
|
|
|
func init() {
|
|
processfunc = translateprocess
|
|
linefunc = translateline
|
|
}
|
|
|
|
func getValuesFromCommas(str string, line int) ([]any, bool) {
|
|
output := []any{}
|
|
temp := []byte{}
|
|
stringlen := len(str)
|
|
for i := 0; i < stringlen; i++ {
|
|
if str[i] == 44 {
|
|
tempstr := string(temp[:])
|
|
resp, worked := processfunc(code{code: tempstr, line: 0})
|
|
if worked {
|
|
output = append(output, resp)
|
|
temp = []byte{}
|
|
continue
|
|
}
|
|
}
|
|
temp = append(temp, str[i])
|
|
}
|
|
tempstr := string(temp[:])
|
|
if tempstr != "" {
|
|
resp, worked := processfunc(code{code: tempstr, line: 0})
|
|
if worked {
|
|
output = append(output, resp)
|
|
} else {
|
|
return nil, false
|
|
}
|
|
}
|
|
return output, true
|
|
}
|
|
|
|
// make a function that converts backslashes in a string to their correct character
|
|
// e.g. "\n" -> newline
|
|
// e.g. "\t" -> tab
|
|
// e.g. "\r" -> carriage return
|
|
// e.g. "\b" -> backspace
|
|
// e.g. "\f" -> formfeed
|
|
// e.g. "\a" -> alert
|
|
// e.g. "\v" -> vertical tab
|
|
// e.g. "\0" -> null
|
|
// e.g. "\'" -> single quote
|
|
// e.g. "\"" -> double quote
|
|
// e.g. "\\" -> backslash
|
|
// e.g. unicode characters like \u00A0 -> unicode
|
|
func unescape(str string) string {
|
|
output := []byte{}
|
|
stringlen := len(str)
|
|
for i := 0; i < stringlen; i++ {
|
|
if str[i] == 92 {
|
|
if i+1 < stringlen {
|
|
i++
|
|
switch str[i] {
|
|
case 110:
|
|
output = append(output, 10)
|
|
case 116:
|
|
output = append(output, 9)
|
|
case 114:
|
|
output = append(output, 13)
|
|
case 98:
|
|
output = append(output, 8)
|
|
case 102:
|
|
output = append(output, 12)
|
|
case 118:
|
|
output = append(output, 11)
|
|
case 120:
|
|
output = append(output, 0)
|
|
case 34:
|
|
output = append(output, 34)
|
|
case 39:
|
|
output = append(output, 39)
|
|
case 92:
|
|
output = append(output, 92)
|
|
case 117:
|
|
if i+4 < stringlen {
|
|
i += 4
|
|
output = append(output, byte(int(str[i])*16*16*16+int(str[i+1])*16*16+int(str[i+2])*16+int(str[i+3])))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
output = append(output, str[i])
|
|
}
|
|
}
|
|
return string(output[:])
|
|
}
|
|
|
|
func getParamNames(str string, line int) []string {
|
|
output := []string{}
|
|
temp := []byte{}
|
|
stringlen := len(str)
|
|
for i := 0; i < stringlen; i++ {
|
|
if str[i] == 44 {
|
|
tempstr := strings.Trim(string(temp[:]), " ")
|
|
if !variableonlyCompile.MatchString(tempstr) {
|
|
log.Fatal("invalid param name on line", line+1)
|
|
}
|
|
output = append(output, tempstr)
|
|
temp = []byte{}
|
|
} else {
|
|
temp = append(temp, str[i])
|
|
}
|
|
}
|
|
tempstr := strings.Trim(string(temp[:]), " ")
|
|
if variableonlyCompile.MatchString(tempstr) {
|
|
output = append(output, tempstr)
|
|
}
|
|
return output
|
|
}
|
|
|
|
func split_by_semicolon_and_newline(str string) []code {
|
|
output := []code{}
|
|
temp := []byte{}
|
|
split := strings.Split(strings.ReplaceAll(str, "\r", ""), "\n")
|
|
splitoutput := []string{}
|
|
for i := 0; i < len(split); i++ {
|
|
if !(skipCompile.MatchString(split[i])) {
|
|
splitoutput = append(splitoutput, split[i])
|
|
}
|
|
}
|
|
str = strings.Join(splitoutput, "\n")
|
|
stringlen := len(str)
|
|
line := 0
|
|
quote := false
|
|
backtick := false
|
|
speech := false
|
|
|
|
for i := 0; i < stringlen; i++ {
|
|
if str[i] == 34 && (len(temp) == 0 || str[i-1] != 92) && !speech && !backtick {
|
|
quote = !quote
|
|
} else if str[i] == 96 && (len(temp) == 0 || str[i-1] != 92) && !speech && !quote {
|
|
backtick = !backtick
|
|
} else if str[i] == 39 && (len(temp) == 0 || str[i-1] != 92) && !quote && !backtick {
|
|
speech = !speech
|
|
}
|
|
if (str[i] == 59 && !quote && !speech && !backtick) || (str[i] == 10 && !backtick) {
|
|
output = append(output, code{code: string(temp[:]), line: line})
|
|
if str[i] == 10 {
|
|
line++
|
|
}
|
|
temp = []byte{}
|
|
} else {
|
|
temp = append(temp, str[i])
|
|
}
|
|
}
|
|
output = append(output, code{code: string(temp[:]), line: line})
|
|
return output
|
|
}
|
|
|
|
var getCodeInIndent = func(i int, codearray []code, isIf bool) ([]code, int) {
|
|
var result []code
|
|
indent := 0
|
|
result = append(result, code{
|
|
code: strings.SplitN(codearray[i].code, "[", 2)[1],
|
|
line: codearray[i].line,
|
|
})
|
|
i++
|
|
for {
|
|
if (closeCompile.MatchString(codearray[i].code) && !switchCloseCompile.MatchString(codearray[i].code)) || (isIf && (elseCompile.MatchString(codearray[i].code) || elseifCompile.MatchString(codearray[i].code))) {
|
|
indent--
|
|
if indent < 0 {
|
|
break
|
|
}
|
|
} else if openCompile.MatchString(codearray[i].code) && !switchCloseCompile.MatchString(codearray[i].code) {
|
|
indent++
|
|
}
|
|
result = append(result, codearray[i])
|
|
i++
|
|
}
|
|
i++
|
|
return result, i
|
|
}
|
|
|
|
var translateprocess = func(codeseg code) (interface{}, bool) {
|
|
for i := 0; i < len(opperators); i++ {
|
|
for j := 0; j < len(opperators[i]); j++ {
|
|
split := strings.Split(codeseg.code, opperators[i][j])
|
|
if len(split) > 1 {
|
|
vals := []any{}
|
|
current := 0
|
|
for k := 0; k < len(split); k++ {
|
|
currentstr := strings.Join(split[current:k], opperators[i][j])
|
|
val, worked := processfunc(code{
|
|
code: currentstr,
|
|
line: codeseg.line,
|
|
})
|
|
if worked {
|
|
vals = append(vals, val)
|
|
current = k
|
|
}
|
|
}
|
|
if len(vals) >= 1 {
|
|
currentstr := strings.Join(split[current:], opperators[i][j])
|
|
val, worked := processfunc(code{
|
|
code: currentstr,
|
|
line: codeseg.line,
|
|
})
|
|
if worked {
|
|
vals = append(vals, val)
|
|
|
|
return opperator{
|
|
t: i,
|
|
vals: vals,
|
|
line: codeseg.line,
|
|
}, true
|
|
} else if len(opperators) == i+1 {
|
|
return nil, false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if stringCompile.MatchString(codeseg.code) {
|
|
return unescape(stringencode(codeseg.code)), true
|
|
} else if functionCompile.MatchString(codeseg.code) {
|
|
str := strings.Trim(codeseg.code, " ")
|
|
bracketsplit := strings.SplitN(str, "(", 2)
|
|
funcname := strings.Trim(bracketsplit[0], " ")
|
|
params := bracketsplit[1][:len(bracketsplit[1])-1]
|
|
paramstranslated, worked := getValuesFromCommas(params, codeseg.line)
|
|
if worked {
|
|
return funcCallType{
|
|
name: funcname,
|
|
args: paramstranslated,
|
|
line: codeseg.line,
|
|
}, true
|
|
}
|
|
} else if bracketsCompile.MatchString(codeseg.code) {
|
|
shorter := strings.Trim(codeseg.code, " ")
|
|
shorter = shorter[1 : len(shorter)-1]
|
|
brackets, ran := processfunc(code{
|
|
code: shorter,
|
|
line: codeseg.line,
|
|
})
|
|
return brackets, ran
|
|
} else if itemsCompiled.MatchString(codeseg.code) {
|
|
inside := strings.Trim(codeseg.code, " ")[1 : len(strings.Trim(codeseg.code, " "))-1]
|
|
vals, worked := getValuesFromCommas(inside, codeseg.line)
|
|
if worked {
|
|
return itemsType{
|
|
vals: vals,
|
|
line: codeseg.line,
|
|
}, true
|
|
}
|
|
} else if numberCompile.MatchString(codeseg.code) {
|
|
if s, err := strconv.ParseFloat(strings.Trim(codeseg.code, " "), 64); err == nil {
|
|
return s, true
|
|
} else {
|
|
log.Fatal(err)
|
|
}
|
|
} else if variableTextCompile.MatchString(codeseg.code) {
|
|
return variable{
|
|
variable: strings.Trim(codeseg.code, " "),
|
|
line: codeseg.line,
|
|
}, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
var translateline = func(i int, codearray []code) (interface{}, int) {
|
|
codeseg := codearray[i]
|
|
if returnStatementCompile.MatchString(codeseg.code) {
|
|
var val any = strings.Trim(codeseg.code, " ")[6:]
|
|
if val != "" {
|
|
respval, worked := translateprocess(code{code: val.(string), line: codeseg.line})
|
|
if !worked {
|
|
log.Fatal("invalid value on line ", codeseg.line+1)
|
|
}
|
|
val = respval
|
|
} else {
|
|
val = nil
|
|
}
|
|
return returnType{
|
|
val: val,
|
|
line: codeseg.line,
|
|
}, i + 1
|
|
} else if breakStatementCompile.MatchString(codeseg.code) {
|
|
return breakType{
|
|
line: codeseg.line,
|
|
}, i + 1
|
|
} else if continueStatementCompile.MatchString(codeseg.code) {
|
|
return continueType{
|
|
line: codeseg.line,
|
|
}, i + 1
|
|
}
|
|
resp, worked := translateprocess(codeseg)
|
|
if worked {
|
|
return resp, i + 1
|
|
} else if setVariableCompile.MatchString(codeseg.code) {
|
|
VAR := strings.Split(codeseg.code, "=")
|
|
firstSplit := strings.Split(strings.Trim(VAR[0], " "), " ")
|
|
TYPE := "var"
|
|
if len(firstSplit) > 1 {
|
|
TYPE = firstSplit[0]
|
|
}
|
|
variable := firstSplit[len(firstSplit)-1]
|
|
resp, worked := translateprocess(code{code: VAR[1],
|
|
line: codeseg.line})
|
|
if !worked {
|
|
log.Fatal("invalid value")
|
|
}
|
|
return setVariable{
|
|
TYPE: TYPE,
|
|
variable: variable,
|
|
value: resp,
|
|
line: codeseg.line,
|
|
}, i + 1
|
|
} else if whileCompile.MatchString(codeseg.code) {
|
|
str := strings.Trim(codeseg.code, " ")
|
|
strlen := len(str)
|
|
str = str[5:strlen]
|
|
split := strings.SplitN(str, "[", 2)
|
|
condition, worked := translateprocess(code{code: split[0],
|
|
line: codeseg.line})
|
|
if !worked {
|
|
log.Fatal("invalid value on line", codeseg.line+1)
|
|
}
|
|
codedata, x := getCodeInIndent(i, codearray, false)
|
|
codeoutput := []interface{}{}
|
|
|
|
codelen := len(codedata)
|
|
for i := 0; i < codelen; {
|
|
resp, x := linefunc(i, codedata)
|
|
i = x
|
|
codeoutput = append(codeoutput, resp)
|
|
}
|
|
|
|
return whileLoop{
|
|
condition: condition,
|
|
code: codeoutput,
|
|
}, x
|
|
} else if ifCompile.MatchString(codeseg.code) {
|
|
str := strings.Trim(codeseg.code, " ")
|
|
strlen := len(str)
|
|
str = str[2:strlen]
|
|
split := strings.SplitN(str, "[", 2)
|
|
condition, worked := translateprocess(code{code: split[0],
|
|
line: codeseg.line})
|
|
if !worked {
|
|
log.Fatal("invalid value on line", codeseg.line+1)
|
|
}
|
|
codedata, x := getCodeInIndent(i, codearray, true)
|
|
codeoutput := []interface{}{}
|
|
|
|
codelen := len(codedata)
|
|
for i := 0; i < codelen; {
|
|
resp, x := linefunc(i, codedata)
|
|
i = x
|
|
codeoutput = append(codeoutput, resp)
|
|
}
|
|
elsecode := []any{}
|
|
elsecodelen := 0
|
|
if elseCompile.MatchString(codearray[x-1].code) {
|
|
codedata, x := getCodeInIndent(x-1, codearray, false)
|
|
elsecodelen = x - 3
|
|
codelen := len(codedata)
|
|
for i := 0; i < codelen; {
|
|
resp, x := linefunc(i, codedata)
|
|
i = x
|
|
elsecode = append(elsecode, resp)
|
|
}
|
|
}
|
|
|
|
return ifstatement{
|
|
condition: condition,
|
|
TRUE: codeoutput,
|
|
FALSE: elsecode,
|
|
}, x + elsecodelen
|
|
} else if subCompile.MatchString(codeseg.code) {
|
|
sub := strings.Trim(codeseg.code, " ")
|
|
sub = sub[4:]
|
|
split := strings.SplitN(sub, "[", 2)
|
|
functioninfo := strings.SplitN(strings.Trim(split[0], " "), "(", 2)
|
|
functionname := functioninfo[0]
|
|
argstr := functioninfo[1]
|
|
argstr = argstr[:len(argstr)-1]
|
|
args := getParamNames(argstr, codeseg.line)
|
|
codedata, x := getCodeInIndent(i, codearray, true)
|
|
codeoutput := []interface{}{}
|
|
|
|
codelen := len(codedata)
|
|
for i := 0; i < codelen; {
|
|
resp, x := linefunc(i, codedata)
|
|
i = x
|
|
codeoutput = append(codeoutput, resp)
|
|
}
|
|
return setFunction{
|
|
name: functionname,
|
|
args: args,
|
|
code: codeoutput,
|
|
}, x
|
|
} else if importCompile.MatchString(codeseg.code) {
|
|
str := strings.Trim(codeseg.code, " ")
|
|
path, worked := processfunc(code{code: str[7:], line: codeseg.line})
|
|
if !worked {
|
|
log.Fatal("invalid import path on line ", codeseg.line+1)
|
|
}
|
|
return importType{
|
|
path: path,
|
|
line: codeseg.line,
|
|
}, i + 1
|
|
} else if skipCompile.MatchString(codeseg.code) {
|
|
} else {
|
|
err := "Invalid syntax on line "
|
|
log.Fatal("\n\nLine " + fmt.Sprint(codeseg.line+1) + ": " + codeseg.code + "\n" + err + "\n\n")
|
|
}
|
|
return nil, i + 1
|
|
}
|
|
|
|
var translate = func(str string) []interface{} {
|
|
code := split_by_semicolon_and_newline(str)
|
|
codelen := len(code)
|
|
output := []interface{}{}
|
|
i := 0
|
|
for i < codelen {
|
|
resp, x := translateline(i, code)
|
|
i = x
|
|
output = append(output, resp)
|
|
}
|
|
return output
|
|
}
|