Compare commits

10 Commits

Author SHA1 Message Date
6c8d014bca First to gitea[
Some checks failed
Build and Deploy on Tag / update-tap (push) Failing after 17s
2026-05-01 08:16:45 -05:00
443984b837 Change docker file 2026-04-16 22:41:50 -05:00
8d574179e6 Change docker file 2026-04-16 22:39:54 -05:00
7d2a68223d add prebuild to build tool 2026-04-16 18:52:24 -05:00
7ad098cef5 Add meta 2026-01-23 05:00:24 -06:00
0a9ae78dbd Add better crosslang 2026-01-22 02:28:35 -06:00
d5906e552c Add better crosslang 2026-01-22 02:27:36 -06:00
3af3f08395 Fix plugin download bug 2026-01-15 00:12:56 -06:00
0890f838d1 Add ability to set icon from template 2025-12-28 13:27:54 -06:00
5b20a64c36 Fix template icon 2025-12-28 13:16:29 -06:00
20 changed files with 788 additions and 64 deletions

64
.gitea/workflows/tag.yaml Normal file
View File

@@ -0,0 +1,64 @@
name: Build and Deploy on Tag
on:
push:
tags:
- 'v*'
env:
VERSION: ${{ gitea.ref_name }}
CLWS_PACKAGE: tesses50/crosslang-withshell
CPKG_PACKAGE: tesses50/cpkg
GITEA_DOMAIN: git.tesses.org
GITEA_REGISTRY_USER: tesses50
jobs:
update-tap:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
cd vscode-extension
npm install
npm install -g typescript
npm install -g @@vscode/vsce
vsce package
cd ..
wget -O /usr/local/bin/crosslang https://redirect.tesses.net/cl-slim-x86_64-linux-musl
chmod 755 /usr/local/bin/crosslang
ln -s /usr/local/bin/crosslang /usr/local/bin/crossc
ln -s /usr/local/bin/crosslang /usr/local/bin/crossint
ln -s /usr/local/bin/crosslang /usr/local/bin/crossvm
crossint ./build.tcross pack
mkdir -p artifacts
cp Tesses.CrossLang.ShellPackage-*.crvm artifacts/ShellPackage.crvm
cp Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-*.crvm artifacts/CPKG.crvm
- name: "Publish artifacts"
uses: akkuman/gitea-release-action@v1
env:
NODE_OPTIONS: '--experimental-fetch' # if nodejs < 18
with:
prerelease: true
files: |-
artifacts/**
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.GITEA_DOMAIN }}
username: ${{ env.GITEA_REGISTRY_USER }}
password: ${{ secrets.PACKAGE_AND_BREW }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ env.GITEA_DOMAIN }}/${{ env.CLWS_PACKAGE }}:latest
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.cpkg
push: true
tags: ${{ env.GITEA_DOMAIN }}/${{ env.CPKG_PACKAGE }}:latest

View File

@@ -47,18 +47,6 @@ jobs:
artifacts: Tesses.CrossLang.PackageServer-*.crvm artifacts: Tesses.CrossLang.PackageServer-*.crvm
condition: SUCCESSFUL condition: SUCCESSFUL
optional: false optional: false
- type: BuildImageStep
name: Build container
dockerfile: Dockerfile
output:
type: RegistryOutput
tags: onedev.site.tesses.net/crosslang/crosslangextras/crosslangextras:latest
registryLogins:
- registryUrl: '@server_url@'
userName: '@job_token@'
passwordSecret: dockersecret
condition: SUCCESSFUL
optional: false
- type: SCPCommandStep - type: SCPCommandStep
name: Copy Shell Package name: Copy Shell Package
privateKeySecret: tesses_www_private_key privateKeySecret: tesses_www_private_key
@@ -66,18 +54,6 @@ jobs:
target: mike@@10.137.42.28:/var/www/downloads/ShellPackage.crvm target: mike@@10.137.42.28:/var/www/downloads/ShellPackage.crvm
condition: SUCCESSFUL condition: SUCCESSFUL
optional: false optional: false
- type: BuildImageStep
name: Build container (package server)
dockerfile: Dockerfile.packageserver
output:
type: RegistryOutput
tags: onedev.site.tesses.net/crosslang/crosslangextras/packageserver:latest
registryLogins:
- registryUrl: '@server_url@'
userName: '@job_token@'
passwordSecret: dockersecret
condition: SUCCESSFUL
optional: false
- type: CommandStep - type: CommandStep
name: Push packages to CPKG name: Push packages to CPKG
runInContainer: true runInContainer: true
@@ -117,6 +93,30 @@ jobs:
useTTY: true useTTY: true
condition: SUCCESSFUL condition: SUCCESSFUL
optional: false optional: false
- type: BuildImageStep
name: Build container
dockerfile: Dockerfile
output:
type: RegistryOutput
tags: onedev.site.tesses.net/crosslang/crosslangextras/crosslangextras:latest
registryLogins:
- registryUrl: '@server_url@'
userName: '@job_token@'
passwordSecret: dockersecret
condition: SUCCESSFUL
optional: false
- type: BuildImageStep
name: Build container (package server)
dockerfile: Dockerfile.packageserver
output:
type: RegistryOutput
tags: onedev.site.tesses.net/crosslang/crosslangextras/packageserver:latest
registryLogins:
- registryUrl: '@server_url@'
userName: '@job_token@'
passwordSecret: dockersecret
condition: SUCCESSFUL
optional: false
- type: CommandStep - type: CommandStep
name: push to coolify name: push to coolify
runInContainer: true runInContainer: true
@@ -124,7 +124,7 @@ jobs:
interpreter: interpreter:
type: DefaultInterpreter type: DefaultInterpreter
commands: | commands: |
curl "$COOLIFY_WEBHOOK" -H "Authorization: Bearer $COOLIFY_TOKEN" curl "$COOLIFY_WEBHOOK" -H "Authorization: Bearer $COOLIFY_TOKEN" > /dev/null
envVars: envVars:
- name: COOLIFY_WEBHOOK - name: COOLIFY_WEBHOOK
value: '@secret:COOLIFY_WEBHOOK@' value: '@secret:COOLIFY_WEBHOOK@'

View File

@@ -1,5 +1,3 @@
FROM onedev.site.tesses.net/crosslang/crosslang:latest FROM git.tesses.org/tesses50/crosslang:latest
COPY ./Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm /root/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm RUN crosslang update-shell
RUN crossarchiveextract /root/Tesses.CrossLang.ShellPackage-1.0.0.0-prod.crvm /root/.config/Tesses/CrossLang

View File

@@ -1,4 +1,4 @@
FROM onedev.site.tesses.net/crosslang/crosslang:latest FROM git.tesses.org/tesses50/crosslang:latest
WORKDIR /app WORKDIR /app
COPY ./Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm /app/Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm COPY ./Tesses.CrossLang.PackageServer/bin/Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm /app/Tesses.CrossLang.PackageServer-1.0.0.0-prod.crvm

View File

@@ -1,2 +1,3 @@
bin bin
obj obj
.DS_Store

View File

@@ -1,2 +1,3 @@
bin bin
obj obj
.DS_Store

View File

@@ -1,2 +1,3 @@
bin bin
obj obj
.DS_Store

View File

@@ -1,2 +1,3 @@
bin bin
obj obj
.DS_Store

View File

@@ -208,7 +208,7 @@ class Tesses.CrossLang.PackageManager
{ {
each(var dep : _vm.Dependencies) each(var dep : _vm.Dependencies)
{ {
var path = /short_name/$"{dep.Name}-{dep.Version.ToString()}"; var path = /short_name/$"{dep.Name}-{dep.Version.ToString()}.crvm";
if(!dirFs.RegularFileExists(path)) if(!dirFs.RegularFileExists(path))
{ {
var pkg2 = this.GetPackage(dep.Name,dep.Version.ToString()); var pkg2 = this.GetPackage(dep.Name,dep.Version.ToString());

View File

@@ -26,7 +26,7 @@ class Tesses.CrossLang.BuildTool
{ {
var dep = this.PackageManager.GetPackage(name,version); var dep = this.PackageManager.GetPackage(name,version);
if(TypeOf(dep) == "Null") throw $"Package {name} with version {version} does not exist"; if(TypeOf(dep) == "Null") throw $"Package {name} with version {version} does not exist";
var pkgPath = dir / $"{name}-{version}.crvm"; var pkgPath = dir / $"{name}-{version}.crvm";
@@ -36,7 +36,7 @@ class Tesses.CrossLang.BuildTool
strm.Close(); strm.Close();
var strm = FS.Local.OpenFile(pkgPath,"rb"); var strm = FS.Local.OpenFile(pkgPath,"rb");
var package = VM.LoadExecutable(strm); var package = VM.LoadExecutable(strm);
strm.Close(); strm.Close();
@@ -64,10 +64,10 @@ class Tesses.CrossLang.BuildTool
{ {
var dir = FS.MakeFull(projectDirectory); var dir = FS.MakeFull(projectDirectory);
var dirStr = dir.ToString(); var dirStr = dir.ToString();
each(var item : this.DirectoriesCompiled) each(var item : this.DirectoriesCompiled)
{ {
if(item.Path == dirStr) return item.Data; if(item.Path == dirStr) return item.Data;
@@ -88,7 +88,7 @@ class Tesses.CrossLang.BuildTool
var icon = ""; var icon = "";
if(TypeOf(configData.compTime) != "Undefined") if(TypeOf(configData.compTime) != "Undefined")
compTime = configData.compTime; compTime = configData.compTime;
if(compTime == "full" && !this.AllowFullCompTime) if(compTime == "full" && !this.AllowFullCompTime)
throw { throw {
Type="CompTimeException", Type="CompTimeException",
@@ -98,12 +98,12 @@ class Tesses.CrossLang.BuildTool
if(TypeOf(configData.name) != "Undefined") if(TypeOf(configData.name) != "Undefined")
name = configData.name; name = configData.name;
if(TypeOf(configData.version) != "Undefined") if(TypeOf(configData.version) != "Undefined")
version = configData.version; version = configData.version;
if(TypeOf(configData.bin_directory) != "Undefined") if(TypeOf(configData.bin_directory) != "Undefined")
outputDir = configData.bin_directory; outputDir = configData.bin_directory;
if(TypeOf(configData.obj_directory) != "Undefined") if(TypeOf(configData.obj_directory) != "Undefined")
objDir = configData.obj_directory; objDir = configData.obj_directory;
if(TypeOf(configData.source_directory) != "Undefined") if(TypeOf(configData.source_directory) != "Undefined")
@@ -113,7 +113,8 @@ class Tesses.CrossLang.BuildTool
if(TypeOf(configData.info) != "Undefined") if(TypeOf(configData.info) != "Undefined")
info = configData.info; info = configData.info;
if(TypeOf(configData.icon) != "Undefined") if(TypeOf(configData.icon) != "Undefined")
icon = (resDir/configData.icon).ToString(); icon = configData.icon;
@@ -121,7 +122,8 @@ class Tesses.CrossLang.BuildTool
if(TypeOf(info.type) == "String" && (info.type == "template" || info.type == "archive")) if(TypeOf(info.type) == "String" && (info.type == "template" || info.type == "archive"))
{ {
//vfs, strm, name, version, info, icon
//vfs, strm, name, version, info
var subdir = new SubdirFilesystem(FS.Local,dir); var subdir = new SubdirFilesystem(FS.Local,dir);
var output = $"{name}-{version}.crvm"; var output = $"{name}-{version}.crvm";
var outFile = FS.Local.OpenFile(dir / outputDir / output,"wb"); var outFile = FS.Local.OpenFile(dir / outputDir / output,"wb");
@@ -135,7 +137,7 @@ class Tesses.CrossLang.BuildTool
} }
FS.WriteAllText(FS.Local, dir / ".crossarchiveignore", ignored); FS.WriteAllText(FS.Local, dir / ".crossarchiveignore", ignored);
} }
FS.CreateArchive(subdir, outFile, name, version, Json.Encode(info),icon); FS.CreateArchive(subdir, outFile, name, version, Json.Encode(info),icon == "" ? "" : (/resDir/icon).ToString());
outFile.Close(); outFile.Close();
subdir.Close(); subdir.Close();
return { return {
@@ -148,13 +150,18 @@ class Tesses.CrossLang.BuildTool
} }
FS.Local.CreateDirectory(dir / objDir / "packages"); FS.Local.CreateDirectory(dir / objDir / "packages");
FS.Local.CreateDirectory(dir / objDir / "res");
FS.Local.CreateDirectory(dir/resDir); FS.Local.CreateDirectory(dir/resDir);
const svfs = new Tesses.CrossLang.SharedViewFilesystem();
svfs.AddFS(new SubdirFilesystem(FS.Local, dir / resDir));
svfs.AddFS(new SubdirFilesystem(FS.Local, dir / objDir / "res"));
var dependencies = []; var dependencies = [];
if(TypeOf(configData.project_dependencies) == "List") if(TypeOf(configData.project_dependencies) == "List")
{ {
each(var dep : configData.project_dependencies) each(var dep : configData.project_dependencies)
{ {
if(Path.FromString(dep).IsRelative()) if(Path.FromString(dep).IsRelative())
{ {
@@ -167,18 +174,18 @@ class Tesses.CrossLang.BuildTool
var sources = []; var sources = [];
if(TypeOf(configData.dependencies) == "List") if(TypeOf(configData.dependencies) == "List")
{ {
each(var dep : configData.dependencies) each(var dep : configData.dependencies)
{ {
dependencies.Add(this.GetPackageDependencies(dep.name,dep.version,dir / objDir / "packages")); dependencies.Add(this.GetPackageDependencies(dep.name,dep.version,dir / objDir / "packages"));
} }
} }
each(var item : this.DirectoriesCompiled) each(var item : this.DirectoriesCompiled)
{ {
if(item.Path == dirStr) return item.Data; if(item.Path == dirStr) return item.Data;
} }
func walk_for_compiling(item,dir2) func walk_for_compiling(item,dir2)
{ {
@@ -200,18 +207,20 @@ class Tesses.CrossLang.BuildTool
env.LoadFileWithDependencies(FS.Local,newFile); env.LoadFileWithDependencies(FS.Local,newFile);
env.GetDictionary().RunTool({ env.GetDictionary().RunTool({
ProjectDirectory = dir,
Project = new SubdirFilesystem(FS.Local, dir), Project = new SubdirFilesystem(FS.Local, dir),
ProjectJson = configData,
ProjectInfo = info, ProjectInfo = info,
GeneratedSource = sources, GeneratedSource = sources,
Config = this.Config Config = this.Config
}); });
} }
else else
{ {
this.copyFile(item.Output, dir2 / $"{item.Name}-{item.Version}.crvm"); this.copyFile(item.Output, dir2 / $"{item.Name}-{item.Version}.crvm");
each(var item2 : item.Dependencies) each(var item2 : item.Dependencies)
{ {
walk_for_compiling(item2, dir2); walk_for_compiling(item2, dir2);
} }
} }
} }
@@ -219,9 +228,65 @@ class Tesses.CrossLang.BuildTool
var file_deps = []; var file_deps = [];
var file_tools = []; var file_tools = [];
if(TypeIsList(configData.prebuild))
{
//do the prebuild things
each(var job : configData.prebuild)
{
if(TypeIsDictionary(job))
{
if(TypeIsString(job.condition))
{
if(!VM.Eval($"return {job.condition};"))
continue;
}
var workdir = dir;
if(TypeIsString(job.workdir))
workdir /= job.workdir;
if(TypeIsList(job.commands))
each(var cmd : job.commands)
{
if(TypeIsList(cmd) && cmd.Length > 0)
{
const name = cmd[0];
const path = Env.GetRealExecutablePath(name).ToString();
cmd.RemoveAt(0);
var p= Process.Start({
FileName = path,
Arguments = cmd,
WorkingDirectory = workdir
});
const result = p.Join();
if(result != 0)
throw $"process: {name}, did not indicate success: {result}";
}
}
if(TypeIsList(job.res))
{
each(var reso : job.res)
{
if(TypeIsString(reso))
{
svfs.AddFS(new SubdirFilesystem(FS.Local, dir / reso));
}
else if(TypeIsDictionary(reso) && TypeIsString(reso.src) && TypeOfString(reso.dest))
{
const mountable = new MountableFilesystem(new Filesystem({}));
mountable.Mount(reso.dest,new SubdirFilesystem(FS.Local, dir / reso.src));
svfs.AddFS(mountable);
}
}
}
}
}
}
each(var dep : dependencies) each(var dep : dependencies)
{ {
if(dep.Info.type == "lib") if(dep.Info.type == "lib")
{ {
file_deps.Add({ file_deps.Add({
Name = dep.Name, Name = dep.Name,
@@ -230,7 +295,7 @@ class Tesses.CrossLang.BuildTool
} }
else if(dep.Info.type == "compile_tool") else if(dep.Info.type == "compile_tool")
{ {
file_tools.Add({ file_tools.Add({
Name = dep.Name, Name = dep.Name,
Version = dep.Version Version = dep.Version
@@ -242,6 +307,7 @@ class Tesses.CrossLang.BuildTool
func walk_for_source(sourceDir) func walk_for_source(sourceDir)
{ {
if(FS.Local.DirectoryExists(sourceDir))
each(var file : FS.Local.EnumeratePaths(sourceDir)) each(var file : FS.Local.EnumeratePaths(sourceDir))
{ {
if(FS.Local.RegularFileExists(file) && file.GetExtension()==".tcross") if(FS.Local.RegularFileExists(file) && file.GetExtension()==".tcross")
@@ -272,7 +338,7 @@ class Tesses.CrossLang.BuildTool
{ {
//dir / outputDir; //dir / outputDir;
var exec = Env.GetRealExecutablePath("git"); var exec = Env.GetRealExecutablePath("git");
var git_hash = ""; var git_hash = "";
@@ -320,9 +386,9 @@ class Tesses.CrossLang.BuildTool
compTimeEnv.RegisterJson(); compTimeEnv.RegisterJson();
compTimeEnv.RegisterRoot(); compTimeEnv.RegisterRoot();
compTimeEnv.RegisterIO(false); compTimeEnv.RegisterIO(false);
dict.FS.Local = new SubdirFilesystem(FS.Local,dir); dict.FS.Local = new SubdirFilesystem(FS.Local,dir);
break; break;
case "full": case "full":
compTimeEnv.RegisterEverything(); compTimeEnv.RegisterEverything();
@@ -336,7 +402,7 @@ class Tesses.CrossLang.BuildTool
compTimeEnv.RegisterJson(); compTimeEnv.RegisterJson();
compTimeEnv.RegisterRoot(); compTimeEnv.RegisterRoot();
compTimeEnv.RegisterIO(false); compTimeEnv.RegisterIO(false);
break; break;
} }
compTimeEnv.LockRegister(); compTimeEnv.LockRegister();
@@ -346,7 +412,7 @@ class Tesses.CrossLang.BuildTool
} }
} }
var result = VM.Compile({ var result = VM.Compile({
Name = name, Name = name,
Version = version, Version = version,
@@ -354,7 +420,7 @@ class Tesses.CrossLang.BuildTool
Info = Json.Encode(info), Info = Json.Encode(info),
Icon = icon, Icon = icon,
Tools = file_tools, Tools = file_tools,
ResourceFileSystem = new SubdirFilesystem(FS.Local, dir / resDir), ResourceFileSystem = svfs,
Dependencies = file_deps, Dependencies = file_deps,
Output = outFile, Output = outFile,
CompTime = compTimeEnv, CompTime = compTimeEnv,
@@ -378,11 +444,10 @@ class Tesses.CrossLang.BuildTool
Path = dirStr, Path = dirStr,
Data = myData Data = myData
}); });
return myData; return myData;
} }
return null; return null;
} }
} }

View File

@@ -0,0 +1,52 @@
func New.Tesses.CrossLang.SharedViewFilesystem()
{
const fileSystems = [];
func enumeratePaths (path) {
var found = [];
each(var fs : fileSystems)
{
if(fs.DirectoryExists(path))
{
each(var ent : fs.EnumeratePaths(path))
{
const name = ent.GetFileName();
if(found.Contains(name)) continue;
found.Add(name);
}
}
}
return found;
}
const fs_dict = {
OpenFile = (path, mode) => {
if(mode == "r" || mode == "rb")
{
each(var fs : fileSystems)
{
if(fs.FileExists(path))
return fs.OpenFile(path,mode);
}
}
return null;
},
EnumeratePaths = enumeratePaths,
Stat = (path) => {
each(var fs : fileSystems)
{
const st = fs.Stat(path);
if(TypeIsDictionary(st)) return st;
}
return null;
},
AddFS = (fs)=>{
fileSystems.Add(fs);
}
};
return new Filesystem(fs_dict);
}

View File

@@ -5,6 +5,7 @@ func Tesses.CrossLang.Shell.Default(dd)
if(flag == "version") if(flag == "version")
{ {
Console.WriteLine($"VM version: {VM.RuntimeVersion}"); Console.WriteLine($"VM version: {VM.RuntimeVersion}");
Console.WriteLine($"Bytecode version: {VM.BytecodeVersion}");
Console.WriteLine($"Shell version: {main.File.Version}"); Console.WriteLine($"Shell version: {main.File.Version}");
Console.WriteLine($"Args version: {Tesses.CrossLang.Args.File.Version}"); Console.WriteLine($"Args version: {Tesses.CrossLang.Args.File.Version}");
Console.WriteLine($"BuildTool version: {Tesses.CrossLang.BuildTool.File.Version}"); Console.WriteLine($"BuildTool version: {Tesses.CrossLang.BuildTool.File.Version}");
@@ -15,6 +16,7 @@ func Tesses.CrossLang.Shell.Default(dd)
Console.WriteLine("COMMANDS:"); Console.WriteLine("COMMANDS:");
Console.WriteLine("new: create new project"); Console.WriteLine("new: create new project");
Console.WriteLine("build: build a project"); Console.WriteLine("build: build a project");
Console.WriteLine("test: test a project");
Console.WriteLine("run: run a project"); Console.WriteLine("run: run a project");
Console.WriteLine("debug: debug a project"); Console.WriteLine("debug: debug a project");
Console.WriteLine("install-console: install a console application"); Console.WriteLine("install-console: install a console application");

View File

@@ -80,6 +80,9 @@ func main(args)
case "publish": case "publish":
return Tesses.CrossLang.Shell.Publish(dd); return Tesses.CrossLang.Shell.Publish(dd);
break; break;
case "test":
return Tesses.CrossLang.Shell.Test(dd);
break;
default: default:
return Tesses.CrossLang.Shell.Default(dd); return Tesses.CrossLang.Shell.Default(dd);
} }

View File

@@ -73,6 +73,7 @@ func Tesses.CrossLang.Shell.New(dd)
proj.version = "1.0.0.0-prod"; proj.version = "1.0.0.0-prod";
var old_info = proj.info; var old_info = proj.info;
proj.info = old_info.template_info; proj.info = old_info.template_info;
proj.icon = old_info.template_icon;
proj.dependencies = old_info.template_project_dependencies; proj.dependencies = old_info.template_project_dependencies;
var srcDir = proj.source_directory; var srcDir = proj.source_directory;
if(TypeOf(srcDir) == "Undefined") srcDir = "/src"; if(TypeOf(srcDir) == "Undefined") srcDir = "/src";

View File

@@ -0,0 +1,386 @@
class ExpectObj {
private inverted=false;
private currentSpec;
private currentTest;
private left;
public getNot() {
this.inverted = !this.inverted;
return this;
}
public ExpectObj(currentTest,currentSpec,left)
{
this.currentTest = currentTest;
this.currentSpec = currentSpec;
this.left = left;
}
public ToBe(right)
{
if(this.inverted)
{
this.SetRes(this.left != right, $"{this.left} is equal to {this.right}");
}
else
{
this.SetRes(this.left == right, $"{this.left} is not equal to {right}");
}
}
public LessThan(right)
{
if(this.inverted)
{
this.SetRes(!(this.left < right), $"{this.left} is less than {this.right}");
}
else
{
this.SetRes(this.left < right, $"{this.left} is not less than {right}");
}
}
public GreaterThan(right)
{
if(this.inverted)
{
this.SetRes(!(this.left > right), $"{this.left} is greater than {this.right}");
}
else
{
this.SetRes(this.left > right, $"{this.left} is not greater than {right}");
}
}
private SetRes(succeeded, failmsg)
{
if(!succeeded)
{
this.currentTest.success = false;
this.currentSpec.pass=false;
this.currentSpec.reason = failmsg;
}
}
}
func Tesses.CrossLang.Shell.Test(dd)
{
var offline=false;
var buildPath = ".";
var nobuild=false;
var allowFullCompTime=false;
var output="";
var debug = false;
each(var flag : dd.Flags)
{
if(flag == "debug")
{
debug = true;
}
else if(flag == "offline")
{
offline = true;
}
else if(flag == "allow-insecure-comptime")
{
allowFullCompTime=true;
}
else if(flag == "help")
{
Console.WriteLine("USAGE: crosslang test [run-flags-and-options] program-arguments...");
Console.WriteLine("USAGE: crosslang test [run-flags-and-options] -- program-arguments-and-options...");
Console.WriteLine("FLAGS:");
Console.WriteLine("offline: build with no internet (don't fetch files)");
Console.WriteLine("allow-insecure-comptime: Allow full comptime");
Console.WriteLine("nobuild: don't build, just run");
Console.WriteLine("debug: emit line info into executable");
Console.WriteLine("help: this help");
Console.WriteLine();
Console.WriteLine("OPTIONS:");
Console.WriteLine("conf=CONFIGSTRING: specify a conf string for compile_tool(s), is the property Config");
return 0;
}
else if(flag == "nobuild")
{
nobuild=true;
}
}
var conf = "";
each(var option : dd.Options)
{
if(option.Key == "conf")
{
conf = option.Value;
}
}
if(nobuild)
{
if(FS.Local.FileExists("cross.json"))
{
var proj = Json.Decode(FS.ReadAllText(FS.Local, "cross.json"));
var nameVer = $"{proj.name}-{proj.version}.crvm";
var buildDir = TypeOf(proj.bin_directory) == "String" ? proj.bin_directory : "bin";
output =./buildDir/nameVer;
if(!FS.Local.FileExists(output))
{
Console.WriteLine($"ERROR: file {output} does not exist.");
}
}
else
{
Console.WriteLine("ERROR: could not find project.");
return 1;
}
}
else
{
var pm = new Tesses.CrossLang.PackageManager();
pm.Offline = offline;
var bt = new Tesses.CrossLang.BuildTool(pm);
bt.Config = conf;
bt.Debug = debug;
bt.AllowFullCompTime = allowFullCompTime;
output = bt.BuildProject(buildPath).Output;
}
return Tesses.CrossLang.Shell.RunTestSuite(output);
}
func Tesses.CrossLang.Shell.RunTestSuite(execFile)
{
var configData = Json.Decode(FS.ReadAllText(FS.Local,"cross.json")) ?? {};
var testDir = configData.test_directory ?? "tests";
var sources = [];
func walk_for_source(sourceDir)
{
if(FS.Local.DirectoryExists(sourceDir))
each(var file : FS.Local.EnumeratePaths(sourceDir))
{
if(FS.Local.RegularFileExists(file) && file.GetExtension()==".tcross")
{
var src = {
FileName = file.ToString(),
Source = FS.ReadAllText(FS.Local, file)
};
sources.Add(src);
}
else if(FS.Local.DirectoryExists(file))
{
walk_for_source(file);
}
}
}
walk_for_source(testDir);
const strm = new MemoryStream(true);
var result = VM.Compile({
Name = "/test/",
Version = "1.0.0.0-prod",
Sources = sources,
Dependencies = [], //they are loaded for us
Output = strm,
CompTime = compTimeEnv,
Debug = this.Debug
});
if(result.Success)
{
const RED = "\e[0;91m";
const GREEN = "\e[0;92m";
const YELLOW = "\e[;93m";
const NC = "\e[0m";
strm.Seek(0,0);
var vmFile = VM.LoadExecutable(strm);
strm.GetBytes().Resize(0);
var env = VM.CreateEnvironment({});
env.RegisterEverything();
env.LockRegister();
env.LoadFileWithDependencies(FS.Local,execFile);
var failed = 0;
var total = 0;
var currentTest = null;
var currentSpec = null;
func Test(name, cb)
{
total++;
currentTest = {
success = true,
specs = []
};
testLists.Add(currentTest);
try {
cb();
if(!currentTest.success)
{
failed++;
Console.WriteLine($"[{RED}FAILED{NC}] {name}");
each(var s : currentTest.specs)
{
if(s.todo)
{
Console.WriteLine($"\t[{YELLOW}TODO{NC}] {s.name}");
}
else if(s.pass)
{
Console.WriteLine($"\t[{GREEN}PASS{NC}] {s.name}");
}
else
{
Console.WriteLine($"\t[{RED}FAILED{NC}] {s.name}");
Console.WriteLine($"\t\tReason: {s.reason}");
}
}
}
else {
Console.WriteLine($"[{GREEN}PASS{NC}] {name}");
each(var s : currentTest.specs)
{
if(s.todo)
{
Console.WriteLine($"\t[{YELLOW}TODO{NC}] {s.name}");
}
else if(s.pass)
{
Console.WriteLine($"\t[{GREEN}PASS{NC}] {s.name}");
}
}
}
} catch(ex)
{
Console.WriteLine($"[{RED}EXCEPTION{NC}] {name}");
Console.WriteLine($"\tReason: {ex}");
each(var s : currentTest.specs)
{
if(s.todo)
{
Console.WriteLine($"\t[{YELLOW}TODO{NC}] {s.name}");
}
else if(s.pass)
{
Console.WriteLine($"\t[{GREEN}PASS{NC}] {s.name}");
}
else
{
Console.WriteLine($"\t[{RED}FAILED{NC}] {s.name}");
Console.WriteLine($"\t\tReason: {s.reason}");
}
}
failed++;
}
currentTest = null;
}
func SpecToDo(name)
{
if(TypeIsDictionary(currentSpec))
{
throw "Must not be in Spec";
}
if(TypeIsDictionary(currentTest))
{
currentTest.specs.Add({
todo = true,
name
});
}
else {
throw "Must be within Test(\"My test name\",()=>{});";
}
}
func Spec(name,cb)
{
if(TypeIsDictionary(currentSpec))
{
throw "Must not be in Spec";
}
if(TypeIsDictionary(currentTest))
{
currentSpec = {
name
};
currentTest.specs.Add(currentSpec);
cb();
currentSpec.pass ??= true;
currentSpec = null;
} else {
throw "Must be within Test(\"My test name\",()=>{});";
}
}
func Expect(val)
{
if(TypeIsDictionary(currentTest) && TypeIsDictionary(currentSpec))
{
return new ExpectObj(currentTest,currentSpec,val);
}
else {
throw "Must be within Spec(\"My spec name\",()=>{});";
}
}
func Assert(val, failmsg)
{
if(TypeIsDictionary(currentTest) && TypeIsDictionary(currentSpec))
{
if(val)
else
{
currentSpec.pass=false;
currentSpec.reason = failmsg;
currentTest.success=false;
}
}
else {
throw "Must be within Spec(\"My spec name\",()=>{});";
}
}
env.SetVariable("Test", Test);
env.SetVariable("Spec", Spec);
env.SetVariable("SpecToDo", SpecToDo);
env.SetVariable("Expect", Expect);
env.SetVariable("Assert",Assert);
const beginTime = DateTime.Now;
try {
env.LoadFile(vmFile);
} catch(ex) {
Console.WriteLine($"[{RED}EXCEPTION{NC}] {ex}");
return 1;
}
Console.WriteLine();
if(failed == 0)
{
Console.WriteLine($"Tests {GREEN}passed{NC} in {(DateTime.Now-beginTime).ToString(true)}");
}
else
{
Console.WriteLine($"Tests {RED}failed{NC} in {(DateTime.Now-beginTime).ToString(true)}");
}
Console.WriteLine($"Passed: {total-failed}");
Console.WriteLine($"Failed: {failed}");
Console.WriteLine($"Total: {total}");
return failed > 0 ? 1 : 0;
}
return 0;
}

View File

@@ -1,6 +1,6 @@
services: services:
pkg: pkg:
image: onedev.site.tesses.net/crosslang/crosslangextras/packageserver:latest image: git.tesses.org/tesses50/cpkg:latest
ports: ports:
- "4206:4206" - "4206:4206"
volumes: volumes:

View File

@@ -17,7 +17,14 @@
"aliases": ["CrossLang", "crosslang"], "aliases": ["CrossLang", "crosslang"],
"extensions": [".tcross"], "extensions": [".tcross"],
"configuration": "./language-configuration.json" "configuration": "./language-configuration.json"
},{ },
{
"id": "bcrosslang",
"aliases": ["Better CrossLang", "better-crosslang"],
"extensions": [".btcross"],
"configuration": "./language-configuration.json"
}
,{
"id": "crossasm", "id": "crossasm",
"aliases": ["CrossAsm", "crossasm"], "aliases": ["CrossAsm", "crossasm"],
"extensions": [".tcasm"], "extensions": [".tcasm"],
@@ -27,6 +34,10 @@
"language": "crosslang", "language": "crosslang",
"scopeName": "source.crosslang", "scopeName": "source.crosslang",
"path": "./syntaxes/crosslang.tmLanguage.json" "path": "./syntaxes/crosslang.tmLanguage.json"
},{
"language": "bcrosslang",
"scopeName": "source.bcrosslang",
"path": "./syntaxes/bcrosslang.tmLanguage.json"
},{ },{
"language": "crossasm", "language": "crossasm",
"scopeName": "source.crossasm", "scopeName": "source.crossasm",

View File

@@ -202,6 +202,7 @@ export async function createTemplate()
if(project_name) if(project_name)
{ {
const dir = join(getDocumentsFolder(),"CrossLangProjects",project_name); const dir = join(getDocumentsFolder(),"CrossLangProjects",project_name);
mkdirSync(join(getDocumentsFolder(),"CrossLangProjects"));
mkdirSync(dir); mkdirSync(dir);
await readCommandToEnd("crosslang",["new",templateName,dir]); await readCommandToEnd("crosslang",["new",templateName,dir]);

View File

@@ -0,0 +1,137 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Better CrossLang",
"patterns": [
{
"include": "#comment"
},
{
"include": "#keywords"
},
{
"include": "#chars"
},
{
"include": "#operators"
},
{
"include": "#function"
},
{
"include": "#identifier"
},
{
"include": "#consts"
},
{
"include": "#double"
},
{
"include": "#long"
},
{
"include": "#strings"
}
],
"repository": {
"comment": {
"patterns": [{
"name": "comment.line.double-slash.bcrosslang",
"begin": "//",
"end": "\\n"
},
{
"name": "comment.block.bcrosslang",
"begin": "\\/\\*",
"end": "\\*\\/"
},
{
"name": "comment.line.bcrosslang",
"begin": "#",
"end": "\\n"
},
{
"name":"comment.block.documentation.bcrosslang",
"begin": "\\/\\^",
"end": "\\^\\/"
}
]
},
"strings": {
"name": "string.quoted.double.bcrosslang",
"begin": "\\\"",
"end": "\\\"",
"patterns": [
{
"name": "constant.character.escape.bcrosslang",
"match": "\\\\."
}
]
},
"operators": {
"patterns": [{
"name": "keyword.operator",
"match": "(\\+|\\-|\\*|\\\/|\\%|\\!|\\||\\&|\\^|\\<\\<|\\>\\>|\\<|\\>|\\=)"
}]
},
"function": {
"patterns": [{
"name": "entity.name.function.bcrosslang",
"match": "\\b[_a-zA-Z\\x80-\\xFF\\$][_a-zA-Z0-9\\x80-\\xFF\\$]*\\("
}]
},
"identifier": {
"patterns": [{
"name": "entity.name.bcrosslang",
"match": "\\b[_a-zA-Z\\x80-\\xFF\\$][_a-zA-Z0-9\\x80-\\xFF\\$]*"
}]
},
"double": {
"name": "constant.numeric.bcrosslang",
"match": "\\b[0-9][0-9]*\\.[0-9]*\\b"
},
"long": {
"patterns": [
{
"name": "constant.numeric.bcrosslang",
"match": "\\b[0-9][0-9]*\\b"
}
]
},
"keywords": {
"patterns": [
{
"name": "constant.language.bcrosslang",
"match": "\\b(true|false|null|undefined|this)\\b"
},
{
"name": "keyword.operator.new.bcrosslang",
"match": "\\bnew\\b"
},
{
"name": "keyword.control.bcrosslang",
"match": "\\b(if|else|while|for|do|return|each|break|try|catch|finally|defer|enumerable|yield|switch|case|default|await|breakpoint|throw)\\b"
},
{
"name": "keyword.bcrosslang",
"match": "\\b(Double|Long|ByteArray|List|Dictionary|Object|String|Char|Callable|Path|Filesystem|Regex|Variant|Boolean|as|var|meta|of|in|interface|delegate|extern|namespace|use|const|func|class|public|private|protected|static|operator|embed|embeddir|embedstrm|comptime|async)\\b"
}
]
},
"chars": {
"name": "constant.character.bcrosslang",
"begin": "'",
"end": "'",
"patterns": [
{
"name": "constant.character.escape.bcrosslang",
"match": "\\\\."
}
]
}
},
"scopeName": "source.bcrosslang"
}

View File

@@ -112,11 +112,11 @@
}, },
{ {
"name": "keyword.control.crosslang", "name": "keyword.control.crosslang",
"match": "\\b(if|else|while|for|do|return|each|break|try|catch|finally|defer|enumerable|yield|switch|case|default|await|breakpoint|throw)\\b" "match": "\\b(if|else|while|for|do|return|each|in|break|continue|try|catch|finally|defer|enumerable|yield|switch|case|default|await|breakpoint|throw)\\b"
}, },
{ {
"name": "keyword.crosslang", "name": "keyword.crosslang",
"match": "\\b(var|const|func|class|public|private|protected|static|operator|embed|embeddir|embedstrm|comptime|async)\\b" "match": "\\b(meta|var|const|func|class|public|private|protected|static|operator|embed|embeddir|embedstrm|comptime|async)\\b"
} }
] ]
}, },