first commit
This commit is contained in:
5
Tesses.CrossLisp.Runtime/.gitignore
vendored
Normal file
5
Tesses.CrossLisp.Runtime/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.DS_Store
|
||||
bin
|
||||
obj
|
||||
publish
|
||||
thumbs.db
|
||||
8
Tesses.CrossLisp.Runtime/cross.json
Normal file
8
Tesses.CrossLisp.Runtime/cross.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https:\/\/crosslang.tesseslanguage.com\/\/schema\/cross-json-schema.json",
|
||||
"info": {
|
||||
"type": "lib"
|
||||
},
|
||||
"name": "Tesses.CrossLisp.Runtime",
|
||||
"version": "1.0.0.0-prod"
|
||||
}
|
||||
462
Tesses.CrossLisp.Runtime/src/mylib.tcross
Normal file
462
Tesses.CrossLisp.Runtime/src/mylib.tcross
Normal file
@@ -0,0 +1,462 @@
|
||||
|
||||
func CrossLisp.isString(v)
|
||||
{
|
||||
if(!TypeIsList(v)) return false;
|
||||
if(v.Length < 2) return false;
|
||||
return v[0] == "$string";
|
||||
}
|
||||
func CrossLisp.getString(v)
|
||||
{
|
||||
if(!CrossLisp.isString(v)) return "";
|
||||
return v[1];
|
||||
}
|
||||
|
||||
func CrossLisp.asCrossLangList(val)
|
||||
{
|
||||
if(TypeIsLong(val)) return val.ToString();
|
||||
if(TypeIsDouble(val)) return val.ToString();
|
||||
if(TypeIsString(val)) return val.Escape(true);
|
||||
|
||||
if(TypeIsList(val))
|
||||
{
|
||||
var str = "[";
|
||||
|
||||
for(var i = 0; i < val.Length; i++)
|
||||
{
|
||||
if(i > 0)
|
||||
str += ", ";
|
||||
str += CrossLisp.asCrossLangList(val[i]);
|
||||
}
|
||||
|
||||
|
||||
return str + "]";
|
||||
}
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
func CrossLisp.toCrossLangExpression(val)
|
||||
{
|
||||
|
||||
|
||||
if(val == "nil") return "[]";
|
||||
if(TypeIsLong(val)) return val.ToString();
|
||||
if(TypeIsDouble(val)) return val.ToString();
|
||||
if(TypeIsString(val)) return val;
|
||||
|
||||
if(TypeIsList(val))
|
||||
{
|
||||
if(val.Length == 0) return "[]";
|
||||
switch(val[0])
|
||||
{
|
||||
case "+":
|
||||
{
|
||||
var fnCall = "(";
|
||||
|
||||
if(val.Length == 1)
|
||||
fnCall += "0";
|
||||
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
fnCall += " + ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
|
||||
return fnCall + ")";
|
||||
}
|
||||
break;
|
||||
case "-":
|
||||
{
|
||||
var fnCall = "(";
|
||||
|
||||
if(val.Length == 1)
|
||||
fnCall += "0";
|
||||
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
fnCall += " - ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
|
||||
return fnCall + ")";
|
||||
}
|
||||
break;
|
||||
case "*":
|
||||
{
|
||||
var fnCall = "(";
|
||||
|
||||
if(val.Length == 1)
|
||||
fnCall += "0";
|
||||
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
fnCall += " * ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
|
||||
return fnCall + ")";
|
||||
}
|
||||
break;
|
||||
case "/":
|
||||
{
|
||||
var fnCall = "(";
|
||||
|
||||
if(val.Length == 1)
|
||||
fnCall += "0";
|
||||
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
fnCall += " / ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
|
||||
return fnCall + ")";
|
||||
}
|
||||
break;
|
||||
case "%":
|
||||
{
|
||||
var fnCall = "(";
|
||||
|
||||
if(val.Length == 1)
|
||||
fnCall += "0";
|
||||
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
fnCall += " % ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
|
||||
return fnCall + ")";
|
||||
}
|
||||
break;
|
||||
case "quote":
|
||||
{
|
||||
if(val.Count > 1)
|
||||
return CrossLisp.asCrossLangList(val[1]);
|
||||
}
|
||||
break;
|
||||
case "call":
|
||||
{
|
||||
if(val.Length >= 3 && CrossLisp.isString(val[2]))
|
||||
{
|
||||
var fnCall = "(" + CrossLisp.toCrossLangExpression(val[1]) + $").{CrossLisp.getString(val[2])}(";
|
||||
for(var i = 3; i < val.Length; i++)
|
||||
{
|
||||
if(i > 3)
|
||||
fnCall += ", ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
return fnCall + ")";
|
||||
}
|
||||
//(call Console "WriteLine" args...)
|
||||
}
|
||||
case "eval":
|
||||
{
|
||||
if(val.Length == 2)
|
||||
{
|
||||
return "VM.Eval(\"return \" + CrossLisp.toCrossLangExpression(" + CrossLisp.toCrossLangExpression(val[1]) + ") + \";\")";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "setq":
|
||||
{
|
||||
//(setq val 42)
|
||||
if(val.Length == 3 && TypeIsString(name))
|
||||
{
|
||||
return "(" + name + "=" + CrossLisp.toCrossLangExpression(val[2]) + ")";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "dict":
|
||||
{
|
||||
var dict = "{";
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
dict += ", ";
|
||||
if(TypeIsList(val[i]) && val[i].Length == 2 && TypeIsString(val[i][0]))
|
||||
{
|
||||
dict += val[i][0] + " = " + CrossLisp.toCrossLangExpression(val[i][1]);
|
||||
}
|
||||
else {
|
||||
throw "Must look like this (dict (key1 value) (key2 value))";
|
||||
}
|
||||
}
|
||||
return dict + "}";
|
||||
}
|
||||
break;
|
||||
case "$string":
|
||||
{
|
||||
if(val.Length == 2)
|
||||
{
|
||||
return val[1].Escape(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
var fnCall = val[0] + "(";
|
||||
|
||||
for(var i = 1; i < val.Length; i++)
|
||||
{
|
||||
if(i > 1)
|
||||
fnCall += ", ";
|
||||
fnCall += CrossLisp.toCrossLangExpression(val[i]);
|
||||
}
|
||||
|
||||
return fnCall + ")";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "[]";
|
||||
}
|
||||
|
||||
func CrossLisp.toCrossLangText(list)
|
||||
{
|
||||
|
||||
|
||||
|
||||
var code = "";
|
||||
each(var item : list)
|
||||
{
|
||||
if(TypeIsList(item) && item.Length > 0)
|
||||
{
|
||||
if(item[0] == "defun")
|
||||
{
|
||||
if(TypeIsString(item[1]))
|
||||
{
|
||||
var hasDoc = false;
|
||||
if(CrossLisp.isString(item[3]))
|
||||
{
|
||||
hasDoc=true;
|
||||
code += "\n/^ " + CrossLisp.getString(item[3]).Replace("^","^^") + " ^/\n";
|
||||
}
|
||||
|
||||
code += $"func {item[1]}(";
|
||||
if(TypeIsList(item[2]))
|
||||
{
|
||||
for(var i = 0; i < item[2].Length; i++)
|
||||
{
|
||||
if(i > 0) code += ", ";
|
||||
code += item[2][i];
|
||||
}
|
||||
}
|
||||
code += "){";
|
||||
for(var i = hasDoc ? 4 : 3; i < item.Length; i++)
|
||||
{
|
||||
if(i + 1 == item.Length)
|
||||
code += "return ";
|
||||
code += CrossLisp.toCrossLangExpression(item[i]);
|
||||
code += ";";
|
||||
}
|
||||
|
||||
code += "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
func CrossLisp.parseLisp(text)
|
||||
{
|
||||
//(+ "Hi" 42)
|
||||
//["+",["$string","Hi"], 42]
|
||||
|
||||
//(+ 'hi 42)
|
||||
//["+",["quote",["hi"]],42]
|
||||
|
||||
var builder = "";
|
||||
|
||||
var tokens = [];
|
||||
|
||||
func flush()
|
||||
{
|
||||
if(builder.Length > 0) {
|
||||
if(builder[0] >= '0' && builder[0] <= '9')
|
||||
{
|
||||
if(builder.Contains("."))
|
||||
{
|
||||
const dbl = ParseDouble(builder);
|
||||
tokens.Add({
|
||||
type = "ident",
|
||||
value = dbl
|
||||
});
|
||||
}
|
||||
else {
|
||||
const lng = ParseLong(builder);
|
||||
tokens.Add({
|
||||
type = "ident",
|
||||
value = lng
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
tokens.Add({
|
||||
type = "ident",
|
||||
value = builder
|
||||
});
|
||||
}
|
||||
|
||||
builder = "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(var i = 0; i < text.Length; i++)
|
||||
{
|
||||
switch(text[i])
|
||||
{
|
||||
case '(':
|
||||
{
|
||||
flush();
|
||||
tokens.Add({
|
||||
type="("
|
||||
});
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
{
|
||||
flush();
|
||||
tokens.Add({
|
||||
type=")"
|
||||
});
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
{
|
||||
flush();
|
||||
tokens.Add({
|
||||
type="'"
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case '\\':
|
||||
builder += text[++i];
|
||||
break;
|
||||
case '\"':
|
||||
{
|
||||
flush();
|
||||
i++;
|
||||
var strtext = "";
|
||||
for(; (i < text.Length) && text[i] != '\"'; i++)
|
||||
{
|
||||
if(text[i] == '\\')
|
||||
{
|
||||
i++;
|
||||
if(i < text.Length)
|
||||
{
|
||||
if(text[i] == 'n')
|
||||
{
|
||||
strtext += "\n";
|
||||
}
|
||||
else if(text[i] == 'r')
|
||||
{
|
||||
strtext += "\r";
|
||||
}
|
||||
else if(text[i] == 't')
|
||||
{
|
||||
strtext += "\t";
|
||||
}
|
||||
else if(text[i] == 'v')
|
||||
{
|
||||
strtext += "\v";
|
||||
}
|
||||
else if(text[i] == 'e')
|
||||
{
|
||||
strtext += "\e";
|
||||
}
|
||||
else if(text[i] == 'x')
|
||||
{
|
||||
if(i + 2 < text.Length)
|
||||
{
|
||||
i++;
|
||||
strtext += Net.Http.UrlPathDecode($"%{text[i]}{text[i+1]}");
|
||||
i++;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
strtext += text[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strtext += text[i];
|
||||
}
|
||||
}
|
||||
tokens.Add({
|
||||
type = "$string",
|
||||
value = strtext
|
||||
});
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
flush();
|
||||
break;
|
||||
default:
|
||||
builder += text[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
flush();
|
||||
|
||||
|
||||
var off = 0;
|
||||
|
||||
|
||||
func parse()
|
||||
{
|
||||
if(tokens[off].type == "'")
|
||||
{
|
||||
off++;
|
||||
return ["quote",parse()];
|
||||
}
|
||||
if(tokens[off].type == "(")
|
||||
{
|
||||
off++;
|
||||
var ls = [];
|
||||
while(tokens[off].type != ")")
|
||||
{
|
||||
ls.Add(parse());
|
||||
}
|
||||
off++;
|
||||
return ls;
|
||||
}
|
||||
|
||||
if(tokens[off].type == "ident")
|
||||
{
|
||||
return tokens[off++].value;
|
||||
}
|
||||
|
||||
if(tokens[off].type == "$string")
|
||||
{
|
||||
return ["$string",tokens[off++].value];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const ls = [];
|
||||
|
||||
while(off < tokens.Length)
|
||||
ls.Add(parse());
|
||||
return ls;
|
||||
}
|
||||
|
||||
//Console.WriteLine(CrossLisp.toCrossLangText(parseLisp("")));
|
||||
Reference in New Issue
Block a user