分享 文言文編程語言 现已支持 Ruby

chrishyman · December 20, 2019 · Last by zzz6519003 replied at December 23, 2019 · 4751 hits

大家可以用这个语言念诗了(大雾)。

https://github.com/LingDong-/wenyan-lang

吾有一數。曰三。名之曰「甲」

Reply to gwq

jia3 = 3 LOL

看这项目的 issue,也是人才辈出

function asc2rb(asc) {
  let rb = rblib;
  let prevfun = "";
  let curlvl = 0;
  let strayvar = 0;
  let lambdaList = [];
  let methodIndex = 0;
  asc = lowerAllPinYinAndMakeItGlobal(asc);
  // console.log("START!",asc)
  function getval(x) {
    if (!x) return "";
    if (x[0] == "ans") {
      strayvar = 0;
      return currTmpVar();
    }
    if (x[0] == "iden") return rename(x[1]);
    if (x[1] == undefined) return "nil";
    return x[1];
  }
  for (let i = 0; i < asc.length; i++) {
    let a = asc[i];
    if (a.args) console.log(a.args, a, "+++++++=======++++_____");
    if (a.op == "var") {
      for (let j = 0; j < a.count; j++) {
        if (a.values[j] == undefined) {
          a.values[j] = [];
        }
        let name = a.names[j];
        if (a.type == "fun") {
          prevfun = name;
          continue;
        }
        let value = getval(a.values[j]);
        if (name == undefined) {
          name = nextTmpVar();
          strayvar++;
        }
        if ([undefined, "nil"].includes(value)) {
          if (a.type == "arr") {
            value = "Ctnr.new";
          } else if (a.type == "num") {
            value = "0";
          } else if (a.type == "str") {
            value = `""`;
          } else if (a.type == "bol") {
            value = "false";
          }
        }
        rb += "\t".repeat(curlvl);
        rb += `${name}=${value}\n`;
      }
    } else if (a.op == "print") {
      rb += "\t".repeat(curlvl);
      rb += `p([`;
      for (let j = 0; j < strayvar; j++) {
        rb += `${prevTmpVar(strayvar - j)}.to_s`;
        if (j != strayvar - 1) {
          rb += ",";
        }
      }
      rb += "].join)\n";
      strayvar = 0;
    } else if (a.op == "fun") {
      rb += "\t".repeat(curlvl);
      let argsStr = a.args.map(arg => arg.name).join(",");
      if (methodIndex == 0) {
        rb += `def ${prevfun}(${argsStr})`;
      } else {
        lambdaList.push(prevfun);
        rb += `${prevfun} = proc {|${argsStr}|`;
      }
      methodIndex++;
    } else if (a.op == "funbody") {
      rb += "\t".repeat(curlvl);
      if (asc[i - 1].op != "fun") {
        if (methodIndex == 0) {
          rb += `def ${prevfun}()`;
        } else {
          lambdaList.push(prevfun);
          rb += `${prevfun} = proc {|_|`;
        }
        methodIndex++;
      }
      rb += "\n";
      curlvl++;
    } else if (a.op == "funend") {
      curlvl--;
      methodIndex--;
      if (methodIndex == 0) {
        rb += `${"\t".repeat(curlvl)}end\n`;
      } else {
        rb += `${"\t".repeat(curlvl)}}`;
      }
      rb += "\n";
    } else if (a.op == "end") {
      curlvl--;
      rb += `${"\t".repeat(curlvl)}end \n`;
    } else if (a.op == "if") {
      rb += "\t".repeat(curlvl);
      rb += "if ";
      let j = 0;
      while (j < a.test.length) {
        if (a.test[j][0] == "cmp") {
          rb += a.test[j][1];
        } else if (a.test[j][0] == "ctnr") {
          if (a.test[j][1] == "subs") {
            if (a.test[j + 1][1] == "rest") {
              rb += ".slice(1)";
            } else {
              if (a.test[j + 1][0] == "lit") {
                rb += "[" + a.test[j + 1][1] + "]";
              } else {
                rb += "[" + a.test[j + 1][1] + "-1]";
              }
            }
            j++;
          } else if (a.test[j][1] == "len") {
            rb += ".length";
          }
        } else {
          rb += a.test[j][1];
        }
        j++;
      }
      rb += "\n";
      curlvl++;
    } else if (a.op == "else") {
      rb += "\t".repeat(curlvl - 1);
      rb += "else\n";
    } else if (a.op == "return") {
      rb += "\t".repeat(curlvl);
      rb += `return ${getval(a.value)}\n`;
    } else if (a.op.startsWith("op")) {
      rb += "\t".repeat(curlvl);
      let lhs = getval(a.lhs);
      let rhs = getval(a.rhs);

      let op = a.op.slice(2);
      if (op in lop) {
        op = lop[op];
      }
      rb += `${nextTmpVar()}=${lhs}${op}${rhs}\n`;
      strayvar++;
    } else if (a.op == "name") {
      for (let j = 0; j < a.names.length; j++) {
        rb += "\t".repeat(curlvl);
        rb += `${a.names[j]}=${prevTmpVar(strayvar - j)}\n`;
      }
      strayvar -= a.names.length;
    } else if (a.op == "call") {
      rb += "\t".repeat(curlvl);
      let functionCallStr = `${a.fun}(${a.args.map(x => getval(x)).join(",")})`;
      if (lambdaList.includes(a.fun)) {
        functionCallStr = `${a.fun}.call(${a.args
          .map(x => getval(x))
          .join(",")})`;
      }
      rb += `${nextTmpVar()}=${functionCallStr}\n`;
      strayvar++;
    } else if (a.op == "subscript") {
      rb += "\t".repeat(curlvl);
      let idx = getval(a.value);
      if (idx == "rest") {
        rb += `${nextTmpVar()}=${a.container}.slice(1)\n`;
        strayvar++;
      } else {
        rb += `${nextTmpVar()}=${a.container}[${idx}${
          a.value[0] == "lit" ? "" : "-1"
        }]\n`;
        strayvar++;
      }
    } else if (a.op == "cat") {
      rb += "\t".repeat(curlvl);
      rb +=
        `${nextTmpVar()}=${a.containers[0]}.concat(` +
        a.containers.slice(1).join(").concat(") +
        ")\n";
      strayvar++;
    } else if (a.op == "push") {
      rb += "\t".repeat(curlvl);
      rb += `${a.container}.push(${a.values.map(x => getval(x)).join(",")})\n`;
    } else if (a.op == "for") {
      rb += "\t".repeat(curlvl);
      rb += `${a.container}.each do |${a.iterator.toLowerCase()}|\n`;
      curlvl++;
    } else if (a.op == "whiletrue") {
      rb += "\t".repeat(curlvl);
      rb += "while true do\n";
      curlvl++;
    } else if (a.op == "whilen") {
      rb += "\t".repeat(curlvl);
      let v = randVar();
      rb += `${getval(a.value)}.times do |${v}|\n`;
      curlvl++;
    } else if (a.op == "break") {
      rb += "\t".repeat(curlvl);
      rb += "break\n";
    } else if (a.op == "not") {
      rb += "\t".repeat(curlvl);
      let v = getval(a.value);
      rb += `${nextTmpVar()}=!${v}\n`;
      strayvar++;
    } else if (a.op == "reassign") {
      rb += "\t".repeat(curlvl);
      let rhs = getval(a.rhs);
      let lhs = getval(a.lhs);
      if (a.lhssubs) {
        lhs += `[${a.lhssubs[1]}${a.lhssubs[0] == "lit" ? "" : "-1"}]`;
      }
      rb += `${lhs}=${rhs}\n`;
    } else if (a.op == "discard") {
      strayvar = 0;
    } else if (a.op == "length") {
      rb += `${nextTmpVar()}=${a.container}.length;`;
      strayvar++;
    } else if (a.op == "comment") {
      rb += "\t".repeat(curlvl);
      rb += `# ${getval(a.value)}\n`;
      rb += "\t".repeat(curlvl);
    } else {
      // console.log(a.op)
    }
  }
  return rb;
}

做这个东西不知道有什么意义,感觉很丑

Reply to zzz6519003

这块要重构,另一份分支做了每个操作符的切分重构。抽象每个 operator 然后上单元测试,在作者之前的代码基础上加 Rust 支持的时候就挺麻烦,所以并行了重构分支和 Rust support 分支。

Reply to chrishyman

有测试就好了 加油!

You need to Sign in before reply, if you don't have an account, please Sign up first.