Codon/codon.js

From Esolang
Jump to navigation Jump to search

This is a function I wrote to execute Codon programs. Given the program as the first parameter and the input as the second parameter, it will return the output. If there is an error compiling, it will log to the console and return no value. If the input is not specified, it will be prompted for every character.


function(program, input) {
    //compiler
    
    program = program.toUpperCase().replace(/#.+/gm, "").match(/\S{3}/gm); //split to groups of 3 characters and remove comments
    let compiled = "" //the codons compiled into characters 0-J
    
    for (codon in program) {
        let amino = ""
        switch (program[codon]) {
            case "GCU":
            case "GCC":
            case "GCA":
            case "GCC":
            amino = "0"; break; //alaline
            case "CGU":
            case "CGC":
            case "CGA":
            case "CGG":
            case "AGA":
            case "AGG":
            amino = "1"; break; //arginine
            case "AAU":
            case "AAC":
            amino = "2"; break; //asparagine
            case "GAU":
            case "GAC":
            amino = "3"; break; //aspartic acid
            case "UGU":
            case "UGC":
            amino = "4"; break; //cysteine
            case "CAA":
            case "CAG":
            amino = "5"; break; //glutamine
            case "GAA":
            case "GAG":
            amino = "6"; break; //glutamic acid
            case "GGU":
            case "GGC":
            case "GGA":
            case "GGG":
            amino = "7"; break; //glycine
            case "CAU":
            case "CAC":
            amino = "8"; break; //histidine
            case "AUU":
            case "AUC":
            case "AUA":
            amino = "9"; break; //Isoleucine
            case "UUA":
            case "UUG":
            case "CUU":
            case "CUC":
            case "CUA":
            case "CUG":
            amino = "A"; break; //Leucine
            case "AAA":
            case "AAG":
            amino = "B"; break; //Lysine
            case "AUG":
            amino = "C"; break; //Methionine
            case "UUU":
            case "UUC":
            amino = "D"; break; //phenylalanine
            case "CCU":
            case "CCC":
            case "CCA":
            case "CCG":
            amino = "E"; break; //proline
            case "UCU":
            case "UCC":
            case "UCA":
            case "UCG":
            case "AGU":
            case "AGC":
            amino = "F"; break; //serine
            case "ACU":
            case "ACC":
            case "ACA":
            case "ACG":
            amino = "G"; break; //threonine
            case "UGG":
            amino = "H"; break; //tryptophan
            case "UAU":
            case "UAC":
            amino = "I"; break; //tyrosine
            case "GUU":
            case "GUG":
            case "GUA":
            case "GUC":
            amino = "J"; break; //valine
            case "UAA":
            case "UAG":
            case "UGA":
            amino = "X"; break; //stop it
        }
        
        if (amino == "") { //if there is no matching amino for the codon
            console.log("error: invalid codon in index "+codon)
            return
        } else {
            compiled += amino
        }
    }
    
    let [start, end] = [compiled.indexOf("C"), compiled.indexOf("X")] //get first methionine and stop codons
    if (start == -1) { //if there's no start
        console.log("error: there is no start codon (AUG)")
        return
    } else if (end == -1) { //if there is no stop codon
        console.log("error: there is no stop codon")
        return
    }
    compiled = compiled.slice(start, end) //cut out anything before start and after stop

    //executor
    
    let out = ""
    let in_i = 0 //input indez
    let a = 0
    let b = 0
    let terminate = false //if true, terminate the program
    let flag = false
    let mem = [] //memory
    
    floor = x => Math.floor(x)
    null0 = x => (x != null || !isNaN(x) ? x : 0)

    for (let pc = 1; pc < compiled.length; pc++) { //start at 1 because of methionine
        switch (compiled[pc]) {
            case "0": //swap registers A and B
                b = [a, a = b][0]
                break
            case "1": //clone A to B
                b = a
                break
            case "2": //clone cell pointed by B to reg B
                a = null0(mem[floor(a)])
                break
            case "3": //clone reg A to cell pointed by B
                mem[floor(b)] = a
                break
            case "4": //flip flag
                flag = !flag
                break
            case "5": //immediate load 2 codons to A
                a = parseInt(compiled.slice(pc+1, pc+3), 20)
                pc+=2
                break
            case "6": //immediade load 4 codons
                a = parseInt(compiled.slice(pc+1, pc+5), 20)
                pc+=4
                break
            case "7": //jump
                if (flag) {
                    pc += floor(a) - 1 //-1 to offset for loop increment
                    pc = (pc < 0 ? 0 : pc > compiled.length ? compiled.length - 1 : pc) //out of bounds fix
                }
                break
            case "8": //input
               if (input) {
                   a = input.charCodeAt(in_i++) || 0
               } else {
                   a = prompt("enter character").charCodeAt(0) || 0
               }
                break
            case "9": //output
                out += String.fromCharCode(floor(a))
                break
            case "A": //add
                a += b
                break
            case "B": //sub
                a -= b
                break
            case "C": //terminate
                terminate = true
            case "D": //multiply
                a *= b
                break
            case "E": //divide
                a /= b
                break
            case "F": //round
                a = Math.round(a)
                break
            case "G": //negate
                a *= -1
                break
            case "H": //a > b
                flag = (a>b?true:false)
                break
            case "I": //a < b
                flag = (a<b?true:false)
                break
            case "J": //a == b
                flag = (a==b?true:false)
                break
        }
        if (terminate) {
            return out
        }
    }
    return out
}