Skip to content

Instantly share code, notes, and snippets.

@saman3d
Last active September 9, 2022 18:56
Show Gist options
  • Select an option

  • Save saman3d/79598f2565a0e566e1f0f15416b9c28f to your computer and use it in GitHub Desktop.

Select an option

Save saman3d/79598f2565a0e566e1f0f15416b9c28f to your computer and use it in GitHub Desktop.
Xulu v1
package main
import (
"bufio"
"errors"
"fmt"
"os"
"regexp"
"strings"
)
// var rawStatement = "abcd abcd aabbc ab a c ccd dede dede cccd cd ascd aaabbcccee aaeeedd dede eeddd ddeeccc cccaabbb ddeeccaa aabbdd ddeeccaa"
var reAlphabet = regexp.MustCompile(`^[a-e]+$`)
var reVerb = regexp.MustCompile(`^(abcd|bcde|dede)$`)
type verb int
const (
v_ADD verb = -3 + iota
v_SUB
v_MUL
)
var textToVerb = map[string]verb{
"abcd": v_ADD,
"bcde": v_SUB,
"dede": v_MUL,
}
var scanner = bufio.NewScanner(os.Stdin)
func main() {
fmt.Println(" Xulu v1 \n Author: saman koushki \n Enter your sentence bellow")
for {
fmt.Print("> ")
scanner.Scan()
raw := scanner.Text()
answer, err := CompileXulu(raw)
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(answer)
}
}
}
// Xulu language is a simple language for writing simple nesting calculations
// Xulu alphabete consists of 5 letters: a b c d e
// with compositing this letters with each other you can represent numbers
// a = 1, b = 2, c = 3, d = 4, e = 5
// here is how:
// each sequence of repeated letters are added to each other. then we calculate mod 5 of them and raise them
// to the power of 2. then sum them up.
// Example:
// aabbcccca
//
// - break this number to its repeated alphabets:
// aa , bb , cccc , a
//
// - now compute its equivalents for every part
// aa = 1 + 1 = 2
// bb = 2 + 2 = 4
// cccc = 3 + 3 + 3 + 3 = 12
// a = 1
//
// - compute mod 5 of each set :
// aa mod 5 = 2
// bb mod 5 = 4
// cccc mod 5 = 2
// a mod 5 = 1
//
// - Now sqaure each number and add them up:
// (2^2) + (4^2) + 2^2 +1 ^ 2 = 25
//
// nouns have no meaning by them selves so they come up with a verb
// which determines the operation that should be done on the nouns to
// reach the answer. there are 3 verbs:
// abcd = addition
// bcde = subtraction
// dede = multiplication
//
// the syntax consists of sentences. sentences are verbs followed by n > 1 number of nouns
// when a verb comes after nother verb it starts a sentence on lower level.
// 3 verbs cannot come after each other.
// a verb cannot come after n < 2 number of nouns
// example:
// v v n n v n n v v n n v n n
// is presented as tree:
// v
// ├── v
// │ ├── n
// │ └── n
// ├── v
// │ ├── n
// │ └── n
// └── v
// ├── v
// │ ├── n
// │ └── n
// └── v
// ├── n
// └── n
func CompileXulu(s string) (int, error) {
// 1. read statement
statement := strings.Split(s, " ")
// 2. validate statement
err := validteStatement(statement)
if err != nil {
return 0, err
}
// 3. calculate statement
return calculateStatementS(statement), nil
}
// translates a Xulu noun to int
func translateNumber(s string) (number int) {
var cache int
for i, v := range []byte(s) {
if i == 0 || s[i-1] == v {
// 1. cache repeated alphabet till we rich another alphabet
cache += int(v - 96)
} else {
// 2. calculate the cache and add to number
cache = (cache % 5)
cache = cache * cache
number += cache
cache = int(v - 96)
}
}
// 3. calculate once more for the last sequence
cache = (cache % 5)
cache = cache * cache
number += cache
return
}
// validates Xulu statement syntax
func validteStatement(s []string) error {
var level int
var c = map[int]int{0: 0} // counting each level children
// the first token should always be a verbs
if !isTokenVerb(s[0]) {
return errors.New("failed to validate statement. invalid token at 0, statements should always start with a verb")
}
for i := 1; i < len(s); i++ {
// -- validate token
if !isTokenValid(s[i]) {
return errors.New("failed to validate statement. invalid token at position " + fmt.Sprint(i))
}
// -- check if token is verb
if isTokenVerb(s[i]) {
// -- check if previous token was verb
if isTokenVerb(s[i-1]) {
// -- increment level members
c[level]++
// -- increment 1 level
level++
c[level] = 0
// -- check if level-2 has more than 2 members cause we're not going back there anymore
if level > 1 && c[level-2] < 2 {
return errors.New("failed to validate statement. invalid syntax at position " + fmt.Sprint(i))
}
} else if level > 0 {
// -- increment level members
c[level-1]++
// -- check if level has more than 2 members
if c[level] < 2 {
return errors.New("failed to validate statement. invalid syntax at position " + fmt.Sprint(i))
}
// -- reset member count
c[level] = 0
} else {
// at the first level there should be no more than one verb wich is the first token
return errors.New("sytax error at position " + fmt.Sprint(i) + ". cannot start another sentence outside a composite sentence.")
}
} else {
// -- increment level members
c[level]++
}
}
// in case we finished and missed to check the previous levels
for l := level; l >= 0; l-- {
if c[l] < 2 {
return errors.New("syntax error invalid nesting.")
}
}
return nil
}
// checks if a token is made of Xulu alphabet using regex
func isTokenValid(s string) bool {
return reAlphabet.Match([]byte(s))
}
// checks if a token is one of (abcd, bcde, dede)
func isTokenVerb(s string) bool {
return reVerb.Match([]byte(s))
}
// calculates Xulu statement using a single stack
func calculateStatementS(s []string) int {
var stack = []int{}
var reserved = 0
// loop in reverse order (there should always be a noun at the end)
// and since there are no closures in the syntax the last sentence is the leaf
for i := len(s) - 1; i >= 0; i-- {
if isTokenVerb(s[i]) {
if isTokenVerb(s[i+1]) {
// we are going one level up so we should sum up the whole stack and reset reserved
// in another words we should sum up the answers of lower level sentences
// therefore one answer remains which is the answer of top level sentence
stack[0] = calculateSentence(textToVerb[s[i]], stack)
stack = stack[:1]
reserved = 0
} else {
// calculate the sentence answer till reserved spot and remove the remaining
// increment reserved so the answer will be preserved for the upper level sentence
stack[len(stack)-reserved-1] = calculateSentence(textToVerb[s[i]], stack[:len(stack)-reserved])
stack = stack[len(stack)-reserved-1:]
reserved++
}
} else {
// append to stack if its a noun
stack = prepend(stack, translateNumber(s[i]))
}
}
return stack[0]
}
// calculates Xulu statement using 2 stacks, one for local stack of only numbers
// the second one is for the main sentences answers
// depricated lol
func calculateStatement(s []string) int {
var mstack = []int{}
var tstack = []int{}
// loop in reverse order (there should always be a noun at the end)
// and since there are no closures in the syntax the last sentence is the leaf
for i := len(s) - 1; i >= 0; i-- {
if isTokenVerb(s[i]) {
if isTokenVerb(s[i+1]) {
// we are going one level up so we should sum up the main stack
// in another words we should sum up the answers of lower level sentences
// therefore one answer remains which is the answerof top level sentence
mstack[0] = calculateSentence(textToVerb[s[i]], mstack)
mstack = mstack[:1]
} else {
// append the sentence answer to main stack and empty the temp stack
// this way level answers are stored in main stack and temp stack is
// ready to take neighbor nouns
mstack = prepend(mstack, calculateSentence(textToVerb[s[i]], tstack))
tstack = tstack[:0]
}
} else {
// append to temp stack if its a noun
tstack = prepend(tstack, translateNumber(s[i]))
}
}
return mstack[0]
}
// calculates answer of nouns using a given verb
func calculateSentence(v verb, values []int) (o int) {
o = values[0]
values = values[1:]
switch v {
case v_ADD:
for _, r := range values {
o += r
}
break
case v_MUL:
for _, r := range values {
o *= r
}
break
case v_SUB:
for _, r := range values {
o -= r
}
break
}
return
}
// adds to the first of int list
// important for order concerns when subtracting
func prepend(l []int, i int) []int {
l = append(l, 0)
copy(l[1:], l)
l[0] = i
return l
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment