├── .github └── workflows │ ├── main.yml │ ├── umbox.yml │ └── umbox │ └── umka_api │ ├── README.md │ └── box.json ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── benchmarks ├── allbench.um ├── expected.log ├── maps.um ├── matrices.ml ├── matrices.py ├── matrices.um ├── matrices.wren ├── nbody.py ├── nbody.um ├── trees.py ├── trees.um ├── trees_nostruct.lua └── trees_nostruct.py ├── box.json ├── build_linux.sh ├── build_linux_mingw.sh ├── build_playground.bat ├── build_playground_linux.sh ├── build_windows_mingw.bat ├── build_windows_msvc.bat ├── doc ├── api.md ├── lang.md └── lib.md ├── editors └── Umka.sublime-syntax ├── examples ├── 3dcam │ ├── 3dcam.c │ ├── 3dcam.md │ ├── 3dcam.png │ ├── 3dcam.um │ ├── build_3dcam_linux.sh │ └── build_3dcam_windows_mingw.bat ├── fractal │ └── fractal.um ├── lisp │ ├── ev.um │ ├── lex.um │ ├── lisp.um │ └── parse.um └── raytracer │ ├── raytracer.png │ └── raytracer.um ├── index.html ├── playground └── umka.js ├── projects ├── libumka.cbp ├── umka.cbp └── umka.workspace ├── resources ├── fem.png ├── lisp.png ├── logo.svg ├── moneyplease.png ├── os.png ├── perf.png ├── spacesim.png ├── stopwar.png ├── tophat.png ├── tractor.png └── vdrift.png ├── run_emscripten.bat ├── run_emscripten_linux.sh ├── runtime ├── embed_runtime_linux.sh ├── embed_runtime_windows_mingw.bat ├── embed_runtime_windows_msvc.bat ├── fnc.um ├── mat.um ├── std.um ├── um2h.um └── utf8.um ├── set_emscripten_paths.bat ├── set_mingw_paths.bat ├── src ├── umka.c ├── umka_api.c ├── umka_api.h ├── umka_common.c ├── umka_common.h ├── umka_compiler.c ├── umka_compiler.h ├── umka_const.c ├── umka_const.h ├── umka_decl.c ├── umka_decl.h ├── umka_expr.c ├── umka_expr.h ├── umka_gen.c ├── umka_gen.h ├── umka_ident.c ├── umka_ident.h ├── umka_lexer.c ├── umka_lexer.h ├── umka_runtime.c ├── umka_runtime.h ├── umka_runtime_src.h ├── umka_stmt.c ├── umka_stmt.h ├── umka_types.c ├── umka_types.h ├── umka_vm.c └── umka_vm.h ├── test_linux.sh ├── test_windows_mingw.bat ├── tests ├── all.um ├── binfileio.um ├── byteconv.um ├── closures.um ├── closures2.um ├── closures3.um ├── compare.um ├── constfold.um ├── countries.dat ├── datetime.um ├── defparam.um ├── dynarrays.um ├── dynarrays2.um ├── dynarrays3.um ├── enums.um ├── errors.um ├── expected.log ├── extlib.um ├── fibers.um ├── fnctools.um ├── forinptr.um ├── fwdtypes.um ├── gc.um ├── gc2.um ├── imports.um ├── imports2.um ├── imports3.um ├── imports4.um ├── interfaces.um ├── interfaces2.um ├── interfaces3.um ├── itemptr.um ├── lib │ ├── build_lib_linux.sh │ ├── build_lib_windows_mingw.bat │ ├── lib.c │ └── lib.um ├── lib1 │ ├── lib1.um │ └── utils.um ├── lib2 │ ├── lib2.um │ └── utils.um ├── maps.um ├── maps2.um ├── multret.um ├── multret2.um ├── nonlocal.um ├── nullstr.um ├── optim.um ├── path with spaces │ ├── a.um │ ├── b.um │ └── module with spaces.um ├── print.um ├── redecl.um ├── safecast.um ├── sorting.um ├── strings.um ├── ternary.um ├── tour.um ├── typeeq.um ├── typeswitch.um ├── untypedlit.um ├── utf8test.um ├── utf8test2.txt ├── utf8test2.um ├── vararg.um ├── vet.um ├── weakptr.um ├── weakptr2.um └── weakptr3.um ├── umbox_post_build.sh └── umbox_pre_build.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the master branch 8 | push: 9 | branches: [ master ] 10 | pull_request: 11 | branches: [ master ] 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | build: 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | os: [ macos-latest, ubuntu-latest ] 23 | 24 | # The operating system of the runner the job will run on 25 | runs-on: ${{ matrix.os }} 26 | 27 | # Steps represent a sequence of tasks that will be executed as part of the job 28 | steps: 29 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 30 | - uses: actions/checkout@v4 31 | 32 | # Build it 33 | - name: build 34 | run: make all 35 | -------------------------------------------------------------------------------- /.github/workflows/umbox.yml: -------------------------------------------------------------------------------- 1 | name: UmBox upload 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | upload: 11 | runs-on: ubuntu-22.04 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - run: sudo apt install -y mingw-w64 16 | - uses: marekmaskarinec/umbox@master 17 | with: 18 | secret: ${{ secrets.UMBOX }} 19 | upload_api: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | with: 24 | path: umka-lang 25 | - run: cp -r umka-lang/.github/workflows/umbox/umka_api/* . 26 | - run: cp umka-lang/src/umka_api.h . 27 | - uses: marekmaskarinec/umbox@master 28 | with: 29 | secret: ${{ secrets.UMBOX_API }} 30 | -------------------------------------------------------------------------------- /.github/workflows/umbox/umka_api/README.md: -------------------------------------------------------------------------------- 1 | # umka_api 2 | 3 | This box is used to distribute the `umka_api.h` header. 4 | -------------------------------------------------------------------------------- /.github/workflows/umbox/umka_api/box.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "umka_api", 3 | "version": "HEAD", 4 | "author": "Vasiliy Tereshkov ", 5 | "license": "BSD-2", 6 | "description": "Umka API C headers", 7 | "readme": "README.md", 8 | "homepage": "https://github.com/vtereshkov/umka-lang", 9 | "dependencies": [], 10 | "include": [ 11 | "umka_api.h", 12 | "LICENSE" 13 | ], 14 | "run": "echo Nothing to run" 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *build/ 3 | *obj/ 4 | src/umka_runtime_src.h 5 | box.tar 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020-2025, Vasiliy Tereshkov 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | 3 | PLATFORM ?= $(shell uname -s) 4 | 5 | BUILD_PATH ?= build 6 | OBJ_PATH ?= obj 7 | 8 | # installation prefix 9 | PREFIX ?= /usr/local 10 | LIBDIR ?= $(PREFIX)/lib 11 | INCLUDEDIR ?= $(PREFIX)/include 12 | BINDIR ?= $(PREFIX)/bin 13 | 14 | # platform specific settings: 15 | ifeq ($(PLATFORM), Linux) 16 | LDFLAGS = -lm -ldl 17 | RANLIB = ar -crs 18 | LIBEXT = so 19 | DYNAMIC_CFLAGS_EXTRA = -shared -fvisibility=hidden 20 | else ifeq ($(PLATFORM), Darwin) 21 | LDFLAGS = 22 | RANLIB = libtool -static -o 23 | LIBEXT = dylib 24 | DYNAMIC_CFLAGS_EXTRA = -dynamiclib -fvisibility=hidden 25 | else ifneq ($(findstring MINGW64_NT,$(PLATFORM)),) 26 | LDFLAGS = -lm 27 | RANLIB = ar -crs 28 | LIBEXT = so 29 | DYNAMIC_CFLAGS_EXTRA = -shared -fvisibility=hidden 30 | endif 31 | 32 | # identical for all platforms: 33 | UMKA_LIB_STATIC = $(BUILD_PATH)/libumka.a 34 | UMKA_LIB_DYNAMIC = $(BUILD_PATH)/libumka.$(LIBEXT) 35 | UMKA_EXE = $(BUILD_PATH)/umka 36 | 37 | CFLAGS = -s -fPIC -O3 -Wall -Wno-format-security -malign-double -fno-strict-aliasing -DUMKA_EXT_LIBS 38 | STATIC_CFLAGS = $(CFLAGS) -DUMKA_STATIC 39 | DYNAMIC_CFLAGS = $(CFLAGS) -DUMKA_BUILD $(DYNAMIC_CFLAGS_EXTRA) 40 | 41 | SRCS = $(filter-out src/umka.c,$(wildcard src/*.c)) 42 | OBJS_STATIC = $(sort $(SRCS:src/%.c=$(OBJ_PATH)/%_static.o)) 43 | OBJS_DYNAMIC = $(sort $(SRCS:src/%.c=$(OBJ_PATH)/%_dynamic.o)) 44 | 45 | APIS = src/umka_api.h 46 | OBJS_EXE = $(OBJ_PATH)/umka_static.o 47 | 48 | all: $(UMKA_EXE) $(UMKA_LIB_STATIC) $(UMKA_LIB_DYNAMIC) 49 | static: $(UMKA_LIB_STATIC) 50 | dynamic: $(UMKA_LIB_DYNAMIC) 51 | exe: $(UMKA_EXE) 52 | 53 | clean: 54 | $(RM) $(BUILD_PATH) $(OBJ_PATH) -r 55 | 56 | install: all 57 | @echo "Installing to the following directories:" 58 | @echo " Libraries: $(DESTDIR)$(LIBDIR)" 59 | @echo " Includes: $(DESTDIR)$(INCLUDEDIR)" 60 | @echo " Binaries: $(DESTDIR)$(BINDIR)" 61 | @mkdir -p -- $(DESTDIR)$(LIBDIR) 62 | @mkdir -p -- $(DESTDIR)$(BINDIR) 63 | @mkdir -p -- $(DESTDIR)$(INCLUDEDIR) 64 | @echo "Copying files..." 65 | @cp $(UMKA_LIB_STATIC) $(DESTDIR)$(LIBDIR)/ 66 | @cp $(UMKA_LIB_DYNAMIC) $(DESTDIR)$(LIBDIR)/ 67 | @cp $(UMKA_EXE) $(DESTDIR)$(BINDIR)/ 68 | @cp $(APIS) $(DESTDIR)$(INCLUDEDIR)/ 69 | @echo "Installation complete!" 70 | 71 | uninstall: 72 | @echo "Uninstalling following files:" 73 | @echo " $(DESTDIR)$(LIBDIR)/libumka.a" 74 | @echo " $(DESTDIR)$(LIBDIR)/libumka.so" 75 | @echo " $(DESTDIR)$(BINDIR)/umka" 76 | @echo " $(DESTDIR)$(INCLUDEDIR)/umka_api.h" 77 | @rm -f -- $(DESTDIR)$(LIBDIR)/libumka.a 78 | @rm -f -- $(DESTDIR)$(LIBDIR)/libumka.so 79 | @rm -f -- $(DESTDIR)$(BINDIR)/umka 80 | @rm -f -- $(DESTDIR)$(INCLUDEDIR)/umka_api.h 81 | @echo "Uninstallation complete!" 82 | 83 | $(UMKA_LIB_STATIC): $(OBJS_STATIC) 84 | @echo AR $@ 85 | @mkdir -p -- $(BUILD_PATH)/include/ 86 | @$(RANLIB) $(UMKA_LIB_STATIC) $^ 87 | @cp $(APIS) $(BUILD_PATH)/include/ 88 | 89 | $(UMKA_LIB_DYNAMIC): $(OBJS_DYNAMIC) 90 | @echo LD $@ 91 | @mkdir -p -- $(BUILD_PATH)/include/ 92 | @$(CC) $(DYNAMIC_CFLAGS) -o $(UMKA_LIB_DYNAMIC) $^ $(LDFLAGS) 93 | @cp $(APIS) $(BUILD_PATH)/include/ 94 | 95 | $(UMKA_EXE): $(OBJS_EXE) $(UMKA_LIB_STATIC) 96 | @echo LD $@ 97 | @mkdir -p -- $(dir $@) 98 | @$(CC) $(STATIC_CFLAGS) -o $(UMKA_EXE) $^ $(LDFLAGS) 99 | 100 | $(OBJ_PATH)/%_static.o: src/%.c 101 | @echo CC $@ 102 | @mkdir -p -- $(dir $@) 103 | @$(CC) $(STATIC_CFLAGS) -o $@ -c $^ 104 | 105 | $(OBJ_PATH)/%_dynamic.o: src/%.c 106 | @echo CC $@ 107 | @mkdir -p -- $(dir $@) 108 | @$(CC) $(DYNAMIC_CFLAGS) -o $@ -c $^ 109 | -------------------------------------------------------------------------------- /benchmarks/allbench.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "std.um" 3 | 4 | "trees.um" 5 | "nbody.um" 6 | "matrices.um" 7 | "maps.um" 8 | ) 9 | 10 | fn benchmark(f: fn ()) { 11 | start := std::clock() 12 | f() 13 | stop := std::clock() 14 | fprintf(std::stderr(), "Time elapsed: %.3f s\n", stop - start) 15 | } 16 | 17 | fn main() { 18 | printf("\n\n>>> Binary trees\n\n"); benchmark({trees::test()}) 19 | printf("\n\n>>> N body problem\n\n"); benchmark({nbody::test(100000)}) 20 | printf("\n\n>>> Matrix multiplication\n\n"); benchmark({matrices::test()}) 21 | printf("\n\n>>> Maps (in order)\n\n"); benchmark({maps::test(100000, false)}) 22 | printf("\n\n>>> Maps (randomized)\n\n"); benchmark({maps::test(100000, true)}) 23 | } -------------------------------------------------------------------------------- /benchmarks/expected.log: -------------------------------------------------------------------------------- 1 | 2 | 3 | >>> Binary trees 4 | 5 | stretch tree of depth 13 check: -1 6 | 8192 trees of depth 4 check: -8192 7 | 2048 trees of depth 6 check: -2048 8 | 512 trees of depth 8 check: -512 9 | 128 trees of depth 10 check: -128 10 | 32 trees of depth 12 check: -32 11 | long lived tree of depth 12 check: -1 12 | 13 | 14 | >>> N body problem 15 | 16 | -0.169075164 17 | -0.169079859 18 | 19 | 20 | >>> Matrix multiplication 21 | 22 | check: -122027500.000000 23 | 24 | 25 | >>> Maps (in order) 26 | 27 | 28 | 29 | >>> Maps (randomized) 30 | 31 | -------------------------------------------------------------------------------- /benchmarks/maps.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test*(n: int, randomize: bool) { 4 | var m: map[int]int 5 | 6 | for i := 0; i < n; i++ { 7 | k := randomize ? std::rand() % n : i 8 | m[k] = -k 9 | } 10 | 11 | for k, v in m { 12 | std::assert(v == -k) 13 | } 14 | } 15 | 16 | fn main() { 17 | test(100000, false) 18 | test(100000, true) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /benchmarks/matrices.ml: -------------------------------------------------------------------------------- 1 | (* Matrix multiplication benchmark - OCaml version *) 2 | 3 | (* To install ocaml: 4 | 1) you need opam >= 2.1 5 | 2) opam switch create 4.12.1+flambda --package=ocaml-variants.4.12.1+options,ocaml-option-flambda 6 | eval `opam env` 7 | opam install ocamlfind mtime --yes 8 | 3) run benchmarks ## Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz 9 | ``` 10 | ✗ ocaml benchmarks/matrices.ml 11 | elapsed: 2.393648 12 | check: -122027500.000000 13 | ✗ wren_cli benchmarks/matrices.wren 14 | elapsed: 6.258158 15 | check: -122027500 16 | ✗ umka_linux/umka benchmarks/matrices.um 17 | elapsed: 7.191 18 | check: -122027500.000000 19 | ✗ python3 benchmarks/matrices.py 20 | elapsed: 11.765505829000176 21 | check: -122027500.0 22 | ``` 23 | *) 24 | 25 | #use "topfind";; 26 | #require "mtime.clock.os";; 27 | 28 | 29 | let size = 400 30 | 31 | let a = Array.init size (fun i -> Array.init size (fun j -> (3. *. (float_of_int i) +. (float_of_int j)))) 32 | let b = Array.init size (fun i -> Array.init size (fun j -> ((float_of_int i) -. 3. *. (float_of_int j)))) 33 | let c = Array.init size (fun _ -> Array.init size (fun _ -> 0.)) 34 | 35 | (* Multiply matrices *) 36 | let start = Mtime_clock.counter ();; 37 | 38 | let () = 39 | for i = 0 to size-1 do 40 | for j = 0 to size-1 do 41 | let s = ref 0.0 in 42 | for k = 0 to size-1 do s := !s +. a.(i).(k) *. b.(k).(j) done; 43 | c.(i).(j) <- !s 44 | done 45 | done 46 | 47 | let () = Printf.printf "elapsed: %f\n%!" (Mtime.Span.to_s (Mtime_clock.count start)) 48 | 49 | (* Check result *) 50 | let check = 51 | let check = ref 0.0 in 52 | for i = 0 to size-1 do 53 | for j = 0 to size-1 do 54 | check := !check +. c.(i).(j) 55 | done 56 | done; 57 | !check 58 | 59 | let () = Printf.printf "check: %f\n" (check /. float_of_int size ** 2.) 60 | -------------------------------------------------------------------------------- /benchmarks/matrices.py: -------------------------------------------------------------------------------- 1 | # Matrix multiplication benchmark - Python version 2 | 3 | import time 4 | 5 | # Python3 has time.perf_counter instead time.clock 6 | try: 7 | time.clock = time.perf_counter 8 | except: 9 | pass 10 | 11 | size = 400 12 | 13 | # Fill matrices 14 | a = [[(3 * i + j) for j in range(size)] for i in range(size)] 15 | b = [[(i - 3 * j) for j in range(size)] for i in range(size)] 16 | c = [[0 for j in range(size)] for i in range(size)] 17 | 18 | # Multiply matrices 19 | start = time.clock() 20 | 21 | for i in range(size): 22 | for j in range(size): 23 | s = 0.0 24 | for k in range(size): s += a[i][k] * b[k][j] 25 | c[i][j] = s 26 | 27 | print("elapsed: " + str(time.clock() - start)) 28 | 29 | # Check result 30 | check = 0.0 31 | for i in range(size): 32 | for j in range(size): check += c[i][j] 33 | 34 | print("check: " + str(check / size**2)) -------------------------------------------------------------------------------- /benchmarks/matrices.um: -------------------------------------------------------------------------------- 1 | // Matrix multiplication benchmark - Umka version 2 | 3 | fn test*() { 4 | const size = 400 5 | var a, b, c: [size][size] real 6 | 7 | // Fill matrices 8 | for i, row in a { 9 | for j in row { 10 | a[i][j] = 3 * i + j 11 | b[i][j] = i - 3 * j 12 | } 13 | } 14 | 15 | // Multiply matrices 16 | for i := 0; i < size; i++ { 17 | for j := 0; j < size; j++ { 18 | s := 0.0 19 | for k := 0; k < size; k++ {s += a[i][k] * b[k][j]} 20 | c[i][j] = s 21 | } 22 | } 23 | 24 | // Check result 25 | check := 0.0 26 | for i, row in c { 27 | for j, col in row {check += col} 28 | } 29 | 30 | printf("check: %lf\n", check / size / size) 31 | } 32 | 33 | fn main() { 34 | test() 35 | } -------------------------------------------------------------------------------- /benchmarks/matrices.wren: -------------------------------------------------------------------------------- 1 | // Matrix multiplication benchmark - Wren version 2 | 3 | var size = 400 4 | var a = [] 5 | var b = [] 6 | var c = [] 7 | 8 | // Fill matrices 9 | for (i in 0...size) { 10 | a.add([]) 11 | b.add([]) 12 | c.add([]) 13 | for (j in 0...size) { 14 | a[i].add(3 * i + j) 15 | b[i].add(i - 3 * j) 16 | c[i].add(0) 17 | } 18 | } 19 | 20 | // Multiply matrices 21 | var start = System.clock 22 | 23 | for (i in 0...size) { 24 | for (j in 0...size) { 25 | var s = 0.0 26 | for (k in 0...size) s = s + a[i][k] * b[k][j] 27 | c[i][j] = s 28 | } 29 | } 30 | 31 | System.print("elapsed: %(System.clock - start)") 32 | 33 | // Check result 34 | var check = 0.0 35 | for (i in 0...size) { 36 | for (j in 0...size) check = check + c[i][j] 37 | } 38 | 39 | System.print("check: %(check / size / size)") 40 | -------------------------------------------------------------------------------- /benchmarks/nbody.py: -------------------------------------------------------------------------------- 1 | # N body problem benchmark - Python version by Kevin Carson 2 | 3 | import sys 4 | 5 | def combinations(l): 6 | result = [] 7 | for x in range(len(l) - 1): 8 | ls = l[x+1:] 9 | for y in ls: 10 | result.append((l[x],y)) 11 | return result 12 | 13 | PI = 3.14159265358979323 14 | SOLAR_MASS = 4 * PI * PI 15 | DAYS_PER_YEAR = 365.24 16 | 17 | BODIES = { 18 | 'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), 19 | 20 | 'jupiter': ([4.84143144246472090e+00, 21 | -1.16032004402742839e+00, 22 | -1.03622044471123109e-01], 23 | [1.66007664274403694e-03 * DAYS_PER_YEAR, 24 | 7.69901118419740425e-03 * DAYS_PER_YEAR, 25 | -6.90460016972063023e-05 * DAYS_PER_YEAR], 26 | 9.54791938424326609e-04 * SOLAR_MASS), 27 | 28 | 'saturn': ([8.34336671824457987e+00, 29 | 4.12479856412430479e+00, 30 | -4.03523417114321381e-01], 31 | [-2.76742510726862411e-03 * DAYS_PER_YEAR, 32 | 4.99852801234917238e-03 * DAYS_PER_YEAR, 33 | 2.30417297573763929e-05 * DAYS_PER_YEAR], 34 | 2.85885980666130812e-04 * SOLAR_MASS), 35 | 36 | 'uranus': ([1.28943695621391310e+01, 37 | -1.51111514016986312e+01, 38 | -2.23307578892655734e-01], 39 | [2.96460137564761618e-03 * DAYS_PER_YEAR, 40 | 2.37847173959480950e-03 * DAYS_PER_YEAR, 41 | -2.96589568540237556e-05 * DAYS_PER_YEAR], 42 | 4.36624404335156298e-05 * SOLAR_MASS), 43 | 44 | 'neptune': ([1.53796971148509165e+01, 45 | -2.59193146099879641e+01, 46 | 1.79258772950371181e-01], 47 | [2.68067772490389322e-03 * DAYS_PER_YEAR, 48 | 1.62824170038242295e-03 * DAYS_PER_YEAR, 49 | -9.51592254519715870e-05 * DAYS_PER_YEAR], 50 | 5.15138902046611451e-05 * SOLAR_MASS) } 51 | 52 | 53 | SYSTEM = list(BODIES.values()) 54 | PAIRS = combinations(SYSTEM) 55 | 56 | 57 | def advance(dt, n, bodies=SYSTEM, pairs=PAIRS): 58 | 59 | for i in range(n): 60 | for (([x1, y1, z1], v1, m1), 61 | ([x2, y2, z2], v2, m2)) in pairs: 62 | dx = x1 - x2 63 | dy = y1 - y2 64 | dz = z1 - z2 65 | mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) 66 | b1m = m1 * mag 67 | b2m = m2 * mag 68 | v1[0] -= dx * b2m 69 | v1[1] -= dy * b2m 70 | v1[2] -= dz * b2m 71 | v2[0] += dx * b1m 72 | v2[1] += dy * b1m 73 | v2[2] += dz * b1m 74 | for (r, [vx, vy, vz], m) in bodies: 75 | r[0] += dt * vx 76 | r[1] += dt * vy 77 | r[2] += dt * vz 78 | 79 | 80 | def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0): 81 | 82 | for (((x1, y1, z1), v1, m1), 83 | ((x2, y2, z2), v2, m2)) in pairs: 84 | dx = x1 - x2 85 | dy = y1 - y2 86 | dz = z1 - z2 87 | e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) 88 | for (r, [vx, vy, vz], m) in bodies: 89 | e += m * (vx * vx + vy * vy + vz * vz) / 2. 90 | print("%.9f" % e) 91 | 92 | def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0): 93 | 94 | for (r, [vx, vy, vz], m) in bodies: 95 | px -= vx * m 96 | py -= vy * m 97 | pz -= vz * m 98 | (r, v, m) = ref 99 | v[0] = px / m 100 | v[1] = py / m 101 | v[2] = pz / m 102 | 103 | def main(n, ref='sun'): 104 | offset_momentum(BODIES[ref]) 105 | report_energy() 106 | advance(0.01, n) 107 | report_energy() 108 | 109 | if __name__ == '__main__': 110 | main(int(sys.argv[1])) 111 | -------------------------------------------------------------------------------- /benchmarks/nbody.um: -------------------------------------------------------------------------------- 1 | // N body problem benchmark - Umka version 2 | 3 | import "std.um" 4 | 5 | type Body = struct { 6 | x, y, z, vx, vy, vz, mass: real 7 | } 8 | 9 | const ( 10 | pi = 3.14159265358979323846 11 | solarMass = 4 * pi * pi 12 | daysPerYear = 365.24 13 | ) 14 | 15 | fn offsetMomentum(b: ^Body, px, py, pz: real) { 16 | b.vx = -px / solarMass 17 | b.vy = -py / solarMass 18 | b.vz = -pz / solarMass 19 | } 20 | 21 | type System = []^Body 22 | 23 | fn NewSystem(body: ^[]Body): System { 24 | sys := make([]^Body, len(body^)) 25 | for i in sys { 26 | sys[i] = &body[i] 27 | } 28 | var px, py, pz: real 29 | for _, body in sys { 30 | px += body.vx * body.mass 31 | py += body.vy * body.mass 32 | pz += body.vz * body.mass 33 | } 34 | offsetMomentum(sys[0], px, py, pz) 35 | return sys 36 | } 37 | 38 | fn energy(sys: ^System): real { 39 | var e: real 40 | for i, body in sys^ { 41 | e += 0.5 * body.mass * (body.vx*body.vx + body.vy*body.vy + body.vz*body.vz) 42 | for j := i + 1; j < len(sys^); j++ { 43 | body2 := sys[j] 44 | dx := body.x - body2.x 45 | dy := body.y - body2.y 46 | dz := body.z - body2.z 47 | distance := sqrt(dx*dx + dy*dy + dz*dz) 48 | e -= (body.mass * body2.mass) / distance 49 | } 50 | } 51 | return e 52 | } 53 | 54 | fn advance(sys: ^System, dt: real) { 55 | for i, body in sys^ { 56 | for j := i + 1; j < len(sys^); j++ { 57 | body2 := sys[j] 58 | dx := body.x - body2.x 59 | dy := body.y - body2.y 60 | dz := body.z - body2.z 61 | 62 | dSquared := dx*dx + dy*dy + dz*dz 63 | distance := sqrt(dSquared) 64 | mag := dt / (dSquared * distance) 65 | 66 | body.vx -= dx * body2.mass * mag 67 | body.vy -= dy * body2.mass * mag 68 | body.vz -= dz * body2.mass * mag 69 | 70 | body2.vx += dx * body.mass * mag 71 | body2.vy += dy * body.mass * mag 72 | body2.vz += dz * body.mass * mag 73 | } 74 | } 75 | 76 | for i, body in sys^ { 77 | body.x += dt * body.vx 78 | body.y += dt * body.vy 79 | body.z += dt * body.vz 80 | } 81 | } 82 | 83 | jupiter := Body{ 84 | x: 4.84143144246472090e+00, 85 | y: -1.16032004402742839e+00, 86 | z: -1.03622044471123109e-01, 87 | vx: 1.66007664274403694e-03 * daysPerYear, 88 | vy: 7.69901118419740425e-03 * daysPerYear, 89 | vz: -6.90460016972063023e-05 * daysPerYear, 90 | mass: 9.54791938424326609e-04 * solarMass} 91 | 92 | saturn := Body{ 93 | x: 8.34336671824457987e+00, 94 | y: 4.12479856412430479e+00, 95 | z: -4.03523417114321381e-01, 96 | vx: -2.76742510726862411e-03 * daysPerYear, 97 | vy: 4.99852801234917238e-03 * daysPerYear, 98 | vz: 2.30417297573763929e-05 * daysPerYear, 99 | mass: 2.85885980666130812e-04 * solarMass} 100 | 101 | uranus := Body{ 102 | x: 1.28943695621391310e+01, 103 | y: -1.51111514016986312e+01, 104 | z: -2.23307578892655734e-01, 105 | vx: 2.96460137564761618e-03 * daysPerYear, 106 | vy: 2.37847173959480950e-03 * daysPerYear, 107 | vz: -2.96589568540237556e-05 * daysPerYear, 108 | mass: 4.36624404335156298e-05 * solarMass} 109 | 110 | neptune := Body{ 111 | x: 1.53796971148509165e+01, 112 | y: -2.59193146099879641e+01, 113 | z: 1.79258772950371181e-01, 114 | vx: 2.68067772490389322e-03 * daysPerYear, 115 | vy: 1.62824170038242295e-03 * daysPerYear, 116 | vz: -9.51592254519715870e-05 * daysPerYear, 117 | mass: 5.15138902046611451e-05 * solarMass} 118 | 119 | sun := Body{ 120 | x: 0, y: 0, z: 0, vx: 0, vy: 0, vz: 0, 121 | mass: solarMass} 122 | 123 | fn test*(iter: int) { 124 | var bodies: []Body = [5]Body{sun, jupiter, saturn, uranus, neptune} 125 | system := NewSystem(&bodies) 126 | printf("%.9f\n", energy(&system)) 127 | for i := 0; i < iter; i++ { 128 | advance(&system, 0.01) 129 | } 130 | printf("%.9f\n", energy(&system)) 131 | } 132 | 133 | fn main() { 134 | if std::argc() == 2 { 135 | test(std::atoi(std::argv(1))) 136 | } 137 | } 138 | 139 | -------------------------------------------------------------------------------- /benchmarks/trees.py: -------------------------------------------------------------------------------- 1 | # Binary trees benchmark - Python version by Antoine Pitrou et al. 2 | 3 | from __future__ import print_function 4 | 5 | import time 6 | 7 | # Python3 has time.perf_counter instead time.clock 8 | try: 9 | time.clock = time.perf_counter 10 | except: 11 | pass 12 | 13 | # Map "range" to an efficient range in both Python 2 and 3. 14 | try: 15 | range = xrange 16 | except NameError: 17 | pass 18 | 19 | class Node: 20 | def __init__(self): 21 | self.item = 0 22 | self.left = None 23 | self.right = None 24 | 25 | def make_tree(item, depth): 26 | node = Node() 27 | node.item = item 28 | if not depth: return node 29 | 30 | item2 = item + item 31 | depth -= 1 32 | 33 | node.left = make_tree(item2 - 1, depth) 34 | node.right = make_tree(item2, depth) 35 | return node 36 | 37 | def check_tree(node): 38 | if not node.left: return node.item 39 | return node.item + check_tree(node.left) - check_tree(node.right) 40 | 41 | min_depth = 4 42 | max_depth = 12 43 | stretch_depth = max_depth + 1 44 | 45 | start = time.clock() 46 | print("stretch tree of depth %d check:" % stretch_depth, check_tree(make_tree(0, stretch_depth))) 47 | 48 | long_lived_tree = make_tree(0, max_depth) 49 | 50 | iterations = 2 ** max_depth 51 | for depth in range(min_depth, stretch_depth, 2): 52 | 53 | check = 0 54 | for i in range(1, iterations + 1): 55 | check += check_tree(make_tree(i, depth)) + check_tree(make_tree(-i, depth)) 56 | 57 | print("%d trees of depth %d check:" % (iterations * 2, depth), check) 58 | iterations //= 4 59 | 60 | print("long lived tree of depth %d check:" % max_depth, check_tree(long_lived_tree)) 61 | print("elapsed: " + str(time.clock() - start)) 62 | -------------------------------------------------------------------------------- /benchmarks/trees.um: -------------------------------------------------------------------------------- 1 | // Binary trees benchmark - Umka version 2 | 3 | type Node = struct { 4 | item: int 5 | left, right: ^Node 6 | } 7 | 8 | fn make_tree(item, depth: int): ^Node { 9 | node := new(Node) 10 | node.item = item 11 | if depth == 0 {return node} 12 | 13 | item2 := item + item 14 | depth-- 15 | 16 | node.left = make_tree(item2 - 1, depth) 17 | node.right = make_tree(item2, depth) 18 | return node 19 | } 20 | 21 | fn check_tree(node: ^Node): int { 22 | if node.left == null {return node.item} 23 | return node.item + check_tree(node.left) - check_tree(node.right) 24 | } 25 | 26 | fn test*() { 27 | const ( 28 | min_depth = 4 29 | max_depth = 12 30 | stretch_depth = max_depth + 1 31 | ) 32 | 33 | stretch_tree := make_tree(0, stretch_depth) 34 | printf("stretch tree of depth %lld check: %lld\n", stretch_depth, check_tree(stretch_tree)) 35 | 36 | long_lived_tree := make_tree(0, max_depth) 37 | 38 | iterations := 1 << max_depth 39 | for depth := min_depth; depth < stretch_depth; depth += 2 { 40 | check := 0 41 | for i := 1; i <= iterations; i++ { 42 | check += check_tree(make_tree(i, depth)) + check_tree(make_tree(-i, depth)) 43 | } 44 | 45 | printf("%lld trees of depth %lld check: %lld\n", iterations * 2, depth, check) 46 | iterations /= 4 47 | } 48 | 49 | printf("long lived tree of depth %lld check: %lld\n", max_depth, check_tree(long_lived_tree)) 50 | } 51 | 52 | fn main() { 53 | test() 54 | } 55 | -------------------------------------------------------------------------------- /benchmarks/trees_nostruct.lua: -------------------------------------------------------------------------------- 1 | -- Binary trees benchmark - Lua version by Mike Pall 2 | 3 | local function BottomUpTree(item, depth) 4 | if depth > 0 then 5 | local i = item + item 6 | depth = depth - 1 7 | local left, right = BottomUpTree(i-1, depth), BottomUpTree(i, depth) 8 | return { item, left, right } 9 | else 10 | return { item } 11 | end 12 | end 13 | 14 | local function ItemCheck(tree) 15 | if tree[2] then 16 | return tree[1] + ItemCheck(tree[2]) - ItemCheck(tree[3]) 17 | else 18 | return tree[1] 19 | end 20 | end 21 | 22 | local N = 12 23 | local mindepth = 4 24 | local maxdepth = mindepth + 2 25 | if maxdepth < N then maxdepth = N end 26 | 27 | local start = os.clock() 28 | 29 | do 30 | local stretchdepth = maxdepth + 1 31 | local stretchtree = BottomUpTree(0, stretchdepth) 32 | io.write(string.format("stretch tree of depth %d check: %d\n", 33 | stretchdepth, ItemCheck(stretchtree))) 34 | end 35 | 36 | local longlivedtree = BottomUpTree(0, maxdepth) 37 | 38 | for depth=mindepth,maxdepth,2 do 39 | local iterations = 2 ^ (maxdepth - depth + mindepth) 40 | local check = 0 41 | for i=1,iterations do 42 | check = check + ItemCheck(BottomUpTree(1, depth)) + 43 | ItemCheck(BottomUpTree(-1, depth)) 44 | end 45 | io.write(string.format("%d trees of depth %d check: %d\n", 46 | iterations*2, depth, check)) 47 | end 48 | 49 | io.write(string.format("long lived tree of depth %d check: %d\n", 50 | maxdepth, ItemCheck(longlivedtree))) 51 | 52 | io.write(string.format("elapsed: %.8f\n", os.clock() - start)) 53 | -------------------------------------------------------------------------------- /benchmarks/trees_nostruct.py: -------------------------------------------------------------------------------- 1 | # Binary trees benchmark - Python version by Antoine Pitrou et al. 2 | 3 | from __future__ import print_function 4 | 5 | import time 6 | 7 | # Python3 has time.perf_counter instead time.clock 8 | try: 9 | time.clock = time.perf_counter 10 | except: 11 | pass 12 | 13 | # Map "range" to an efficient range in both Python 2 and 3. 14 | try: 15 | range = xrange 16 | except NameError: 17 | pass 18 | 19 | def make_tree(item, depth): 20 | if not depth: return item, None, None 21 | item2 = item + item 22 | depth -= 1 23 | return item, make_tree(item2 - 1, depth), make_tree(item2, depth) 24 | 25 | def check_tree(node): 26 | item, left, right = node 27 | if not left: return item 28 | return item + check_tree(left) - check_tree(right) 29 | 30 | min_depth = 4 31 | max_depth = 12 32 | stretch_depth = max_depth + 1 33 | 34 | start = time.clock() 35 | print("stretch tree of depth %d check:" % stretch_depth, check_tree(make_tree(0, stretch_depth))) 36 | 37 | long_lived_tree = make_tree(0, max_depth) 38 | 39 | iterations = 2 ** max_depth 40 | for depth in range(min_depth, stretch_depth, 2): 41 | 42 | check = 0 43 | for i in range(1, iterations + 1): 44 | check += check_tree(make_tree(i, depth)) + check_tree(make_tree(-i, depth)) 45 | 46 | print("%d trees of depth %d check:" % (iterations * 2, depth), check) 47 | iterations //= 4 48 | 49 | print("long lived tree of depth %d check:" % max_depth, check_tree(long_lived_tree)) 50 | print("elapsed: " + str(time.clock() - start)) 51 | -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "umka", 3 | "version": "v1.5.4", 4 | "author": "Vasiliy Tereshkov ", 5 | "license": "BSD-2", 6 | "description": "The Umka programming language", 7 | "readme": "README.md", 8 | "source": "https://github.com/vtereshkov/umka-lang", 9 | "homepage": "https://github.com/vtereshkov/umka-lang", 10 | "dependencies": [], 11 | "include": [ 12 | "umka.exe", 13 | "umka", 14 | "libumka.dll", 15 | "libumka.so", 16 | "libumka_static_windows.a", 17 | "libumka_static_linux.a", 18 | "umka_api.h" 19 | ], 20 | "pre_build": "sh umbox_pre_build.sh", 21 | "post_build": "sh umbox_post_build.sh", 22 | "run": "make" 23 | } 24 | -------------------------------------------------------------------------------- /build_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gccwflags="-Wall -Wno-format-security" 4 | gccflags="-s -fPIC -O3 -malign-double -fno-strict-aliasing -fvisibility=hidden -DUMKA_BUILD -DUMKA_EXT_LIBS $gccwflags" 5 | sourcefiles="umka_api.c umka_common.c umka_compiler.c umka_const.c umka_decl.c umka_expr.c 6 | umka_gen.c umka_ident.c umka_lexer.c umka_runtime.c umka_stmt.c umka_types.c umka_vm.c" 7 | 8 | rm umka_linux -rf 9 | 10 | cd src 11 | 12 | rm -f *.o 13 | rm -f *.a 14 | 15 | gcc $gccflags -c $sourcefiles 16 | gcc -s -shared -fPIC -static-libgcc *.o -o libumka.so -lm -ldl 17 | ar rcs libumka_static_linux.a *.o 18 | 19 | gcc $gccflags -c umka.c 20 | gcc -s umka.o -o umka -static-libgcc -L$PWD -lm -lumka -Wl,-rpath,'$ORIGIN' 21 | 22 | rm -f *.o 23 | 24 | cd .. 25 | 26 | mkdir umka_linux/examples/3dcam -p 27 | mkdir umka_linux/examples/fractal -p 28 | mkdir umka_linux/examples/lisp -p 29 | mkdir umka_linux/examples/raytracer -p 30 | mkdir umka_linux/doc 31 | mkdir umka_linux/editors 32 | 33 | mv src/libumka* src/umka umka_linux/ 34 | cp src/umka_api.h LICENSE umka_linux/ 35 | 36 | cp examples/* umka_linux/examples -r 37 | cp doc/* umka_linux/doc 38 | cp editors/* umka_linux/editors 39 | 40 | echo Build finished 41 | -------------------------------------------------------------------------------- /build_linux_mingw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | gccwflags="-Wall -Wno-format-security" 4 | gccflags="-s -fPIC -O3 -malign-double -fno-strict-aliasing -fvisibility=hidden -DUMKA_BUILD -DUMKA_EXT_LIBS $gccwflags" 5 | sourcefiles="umka_api.c umka_common.c umka_compiler.c umka_const.c umka_decl.c umka_expr.c 6 | umka_gen.c umka_ident.c umka_lexer.c umka_runtime.c umka_stmt.c umka_types.c umka_vm.c" 7 | 8 | rm umka_windows_mingw -rf 9 | 10 | cd src 11 | 12 | rm -f *.o 13 | rm -f *.a 14 | 15 | x86_64-w64-mingw32-gcc $gccflags -c $sourcefiles 16 | x86_64-w64-mingw32-gcc -s -shared -fPIC -static-libgcc *.o -o libumka.dll -lm 17 | ar rcs libumka_static_windows.a *.o 18 | 19 | x86_64-w64-mingw32-gcc $gccflags -c umka.c 20 | x86_64-w64-mingw32-gcc -s umka.o -o umka.exe -static-libgcc -lm -L. -lumka -Wl,-rpath,'$ORIGIN' 21 | 22 | rm -f *.o 23 | 24 | cd .. 25 | 26 | mkdir umka_windows_mingw/examples/3dcam -p 27 | mkdir umka_windows_mingw/examples/fractal -p 28 | mkdir umka_windows_mingw/examples/lisp -p 29 | mkdir umka_windows_mingw/examples/raytracer -p 30 | mkdir umka_windows_mingw/doc 31 | mkdir umka_windows_mingw/editors 32 | 33 | mv src/libumka* src/umka.exe umka_windows_mingw/ 34 | cp src/umka_api.h LICENSE umka_windows_mingw/ 35 | 36 | cp examples/* umka_windows_mingw/examples -r 37 | cp doc/* umka_windows_mingw/doc 38 | cp editors/* umka_windows_mingw/editors 39 | 40 | echo Build finished 41 | -------------------------------------------------------------------------------- /build_playground.bat: -------------------------------------------------------------------------------- 1 | cd src 2 | cmd /c ..\run_emscripten.bat 3 | cd .. 4 | 5 | mkdir playground 6 | move /y src\umka.js playground 7 | 8 | -------------------------------------------------------------------------------- /build_playground_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd src 3 | sh -c ../run_emscripten_linux.sh 4 | cd .. 5 | 6 | mkdir playground 7 | mv src/umka.js playground 8 | -------------------------------------------------------------------------------- /build_windows_mingw.bat: -------------------------------------------------------------------------------- 1 | cd src 2 | 3 | gcc -s -O3 -malign-double -fno-strict-aliasing -fvisibility=hidden -DUMKA_BUILD -DUMKA_EXT_LIBS -Wall -Wno-format-security -c umka_api.c umka_common.c umka_compiler.c umka_const.c umka_decl.c umka_expr.c umka_gen.c umka_ident.c umka_lexer.c umka_runtime.c umka_stmt.c umka_types.c umka_vm.c 4 | gcc -s -shared -Wl,--output-def=libumka.def -Wl,--out-implib=libumka.a -Wl,--dll *.o -o libumka.dll -static-libgcc -static 5 | ar rcs libumka_static_windows.a *.o 6 | 7 | gcc -s -O3 -malign-double -fno-strict-aliasing -Wall -c umka.c 8 | gcc -s umka.o -o umka.exe -static-libgcc -static -L%cd% -lm -lumka 9 | 10 | del *.o 11 | cd .. 12 | 13 | mkdir umka_windows_mingw 14 | 15 | move /y src\libumka* umka_windows_mingw 16 | move /y src\umka.exe umka_windows_mingw 17 | copy src\umka_api.h umka_windows_mingw 18 | copy LICENSE umka_windows_mingw 19 | 20 | mkdir umka_windows_mingw\examples 21 | mkdir umka_windows_mingw\examples\3dcam 22 | mkdir umka_windows_mingw\examples\fractal 23 | mkdir umka_windows_mingw\examples\lisp 24 | mkdir umka_windows_mingw\examples\raytracer 25 | mkdir umka_windows_mingw\doc 26 | mkdir umka_windows_mingw\editors 27 | 28 | copy examples\3dcam\*.* umka_windows_mingw\examples\3dcam 29 | copy examples\fractal\*.* umka_windows_mingw\examples\fractal 30 | copy examples\lisp\*.* umka_windows_mingw\examples\lisp 31 | copy examples\raytracer\*.* umka_windows_mingw\examples\raytracer 32 | copy doc\*.* umka_windows_mingw\doc 33 | copy editors\*.* umka_windows_mingw\editors 34 | -------------------------------------------------------------------------------- /build_windows_msvc.bat: -------------------------------------------------------------------------------- 1 | cd src 2 | 3 | cl /nologo /O2 /MT /LD /Felibumka.dll /DUMKA_BUILD /DUMKA_EXT_LIBS umka_api.c umka_common.c umka_compiler.c umka_const.c umka_decl.c umka_expr.c umka_gen.c umka_ident.c umka_lexer.c umka_runtime.c umka_stmt.c umka_types.c umka_vm.c 4 | lib /nologo /out:libumka_static.lib *.obj 5 | 6 | cl /nologo /O2 /MT /Feumka.exe umka.c libumka.lib 7 | 8 | del *.obj 9 | cd .. 10 | 11 | mkdir umka_windows_msvc 12 | 13 | move /y src\libumka* umka_windows_msvc 14 | move /y src\umka.exe umka_windows_msvc 15 | copy src\umka_api.h umka_windows_msvc 16 | copy LICENSE umka_windows_msvc 17 | 18 | mkdir umka_windows_msvc\examples 19 | mkdir umka_windows_msvc\examples\3dcam 20 | mkdir umka_windows_msvc\examples\fractal 21 | mkdir umka_windows_msvc\examples\lisp 22 | mkdir umka_windows_msvc\examples\raytracer 23 | mkdir umka_windows_msvc\doc 24 | mkdir umka_windows_msvc\editors 25 | 26 | copy examples\3dcam\*.* umka_windows_msvc\examples\3dcam 27 | copy examples\fractal\*.* umka_windows_msvc\examples\fractal 28 | copy examples\lisp\*.* umka_windows_msvc\examples\lisp 29 | copy examples\raytracer\*.* umka_windows_msvc\examples\raytracer 30 | copy doc\*.* umka_windows_msvc\doc 31 | copy editors\*.* umka_windows_msvc\editors 32 | -------------------------------------------------------------------------------- /examples/3dcam/3dcam.c: -------------------------------------------------------------------------------- 1 | // Umka embedded scripting example (original raylib example by Ramon Santamaria) 2 | 3 | #include 4 | #include "raylib.h" 5 | #include "umka_api.h" 6 | 7 | 8 | // Umka extension functions 9 | void rlDrawPlane(UmkaStackSlot *params, UmkaStackSlot *result) 10 | { 11 | Vector3 *centerPos = (Vector3 *)umkaGetParam(params, 0); 12 | Vector2 *size = (Vector2 *)umkaGetParam(params, 1); 13 | Color *color = (Color *)umkaGetParam(params, 2); 14 | 15 | DrawPlane(*centerPos, *size, *color); 16 | } 17 | 18 | 19 | void rlDrawCube(UmkaStackSlot *params, UmkaStackSlot *result) 20 | { 21 | Vector3 *position = (Vector3 *)umkaGetParam(params, 0); 22 | float width = umkaGetParam(params, 1)->realVal; 23 | float height = umkaGetParam(params, 2)->realVal; 24 | float length = umkaGetParam(params, 3)->realVal; 25 | Color *color = (Color *)umkaGetParam(params, 4); 26 | 27 | DrawCube(*position, width, height, length, *color); 28 | } 29 | 30 | 31 | int main(void) 32 | { 33 | // Umka initialization 34 | UmkaFuncContext umkaInitBodies = {0}, umkaDrawBodies = {0}; 35 | void *umka = umkaAlloc(); 36 | bool umkaOk = umkaInit(umka, "3dcam.um", NULL, 1024 * 1024, NULL, 0, NULL, false, false, NULL); 37 | 38 | if (umkaOk) 39 | { 40 | umkaAddFunc(umka, "drawPlane", &rlDrawPlane); 41 | umkaAddFunc(umka, "drawCube", &rlDrawCube); 42 | 43 | umkaAddModule(umka, "rl.um", 44 | "type Vector2* = struct {x, y: real32}\n" 45 | "type Vector3* = struct {x, y, z: real32}\n" 46 | "type Color* = struct {r, g, b, a: uint8}\n" 47 | "fn drawPlane*(centerPos: Vector3, size: Vector2, color: Color)\n" 48 | "fn drawCube*(position: Vector3, width, height, length: real, color: Color)\n" 49 | ); 50 | 51 | umkaOk = umkaCompile(umka); 52 | } 53 | 54 | if (umkaOk) 55 | { 56 | printf("Umka initialized\n"); 57 | umkaGetFunc(umka, NULL, "initBodies", &umkaInitBodies); 58 | umkaGetFunc(umka, NULL, "drawBodies", &umkaDrawBodies); 59 | } 60 | else 61 | { 62 | UmkaError *error = umkaGetError(umka); 63 | printf("Umka error %s (%d, %d): %s\n", error->fileName, error->line, error->pos, error->msg); 64 | } 65 | 66 | // Raylib initialization 67 | const int screenWidth = 800; 68 | const int screenHeight = 450; 69 | 70 | InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person"); 71 | 72 | // Define the camera to look into our 3D world (position, target, up vector) 73 | Camera camera = { 0 }; 74 | camera.position = (Vector3){ 4.0f, 2.0f, 4.0f }; 75 | camera.target = (Vector3){ 0.0f, 1.8f, 0.0f }; 76 | camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; 77 | camera.fovy = 60.0f; 78 | 79 | if (umkaOk) 80 | umkaOk = umkaCall(umka, &umkaInitBodies) == 0; 81 | 82 | if (!umkaOk) 83 | { 84 | UmkaError *error = umkaGetError(umka); 85 | printf("Umka runtime error %s (%d): %s\n", error->fileName, error->line, error->msg); 86 | } 87 | 88 | SetTargetFPS(60); // Set our game to run at 60 frames per second 89 | 90 | int exitCode = 0; 91 | 92 | // Main game loop 93 | if (umkaOk) 94 | { 95 | while (!WindowShouldClose()) // Detect window close button or ESC key 96 | { 97 | UpdateCamera(&camera, CAMERA_FIRST_PERSON); 98 | BeginDrawing(); 99 | 100 | ClearBackground((Color){ 190, 190, 255, 255 }); 101 | 102 | BeginMode3D(camera); 103 | 104 | exitCode = umkaCall(umka, &umkaDrawBodies); 105 | if (!umkaAlive(umka)) 106 | { 107 | if (exitCode != 0) 108 | { 109 | UmkaError *error = umkaGetError(umka); 110 | printf("Umka runtime error %s (%d): %s\n", error->fileName, error->line, error->msg); 111 | } 112 | break; 113 | } 114 | 115 | EndMode3D(); 116 | 117 | DrawRectangle( 10, 10, 220, 70, Fade(SKYBLUE, 0.5f)); 118 | DrawRectangleLines( 10, 10, 220, 70, BLUE); 119 | 120 | DrawText("First person camera default controls:", 20, 20, 10, BLACK); 121 | DrawText("- Move with keys: W, A, S, D", 40, 40, 10, DARKGRAY); 122 | DrawText("- Mouse move to look around", 40, 60, 10, DARKGRAY); 123 | 124 | EndDrawing(); 125 | } 126 | } 127 | 128 | // Raylib de-initialization 129 | CloseWindow(); // Close window and OpenGL context 130 | 131 | // Umka de-initialization 132 | umkaFree(umka); 133 | 134 | return exitCode; 135 | } 136 | -------------------------------------------------------------------------------- /examples/3dcam/3dcam.md: -------------------------------------------------------------------------------- 1 | # Build instructions 2 | 3 | ## Windows (MinGW) 4 | 5 | * Copy the following files to the `examples\3dcam` folder: 6 | - From raylib distribution: 7 | - `raylib.dll` 8 | - `libraylibdll.a` 9 | - `raylib.h` 10 | - From MinGW distribution 11 | - `libwinpthead-1.dll` 12 | * Add MinGW paths to the `PATH` environment variable 13 | * Run `build_3dcam_windows_mingw.bat` 14 | * Run `3dcam.exe` 15 | 16 | ## Linux 17 | 18 | * Copy the following files to the `examples/3dcam` folder: 19 | - From raylib distribution (assuming the latest raylib version to be 4.5): 20 | - `libraylib.so` 21 | - `libraylib.so.4.5.0` 22 | - `libraylib.so.450` 23 | - `raylib.h` 24 | * Run `./build_3dcam_linux.sh` 25 | * Run `./3dcam` 26 | -------------------------------------------------------------------------------- /examples/3dcam/3dcam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/examples/3dcam/3dcam.png -------------------------------------------------------------------------------- /examples/3dcam/3dcam.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "std.um" 3 | "rl.um" 4 | ) 5 | 6 | const maxColumns = 20 7 | 8 | var cubes: [maxColumns] struct { 9 | height: real 10 | position: rl::Vector3 11 | color: rl::Color 12 | } 13 | 14 | fn rnd(min, max: real): real {return min + (max - min) * std::frand()} 15 | 16 | fn initBodies() { 17 | // Generates some random columns 18 | std::srand(std::time()) 19 | for _, cube^ in cubes { 20 | cube.height = rnd(1, 12); 21 | cube.position = {rnd(-15, 15), cube.height / 2, rnd(-15, 15)} 22 | cube.color = {round(rnd(40, 150)), round(rnd(40, 60)), 40, 255} 23 | } 24 | } 25 | 26 | fn drawBodies() { 27 | // Draw ground 28 | rl::drawPlane({0, 0, 0}, {32, 32}, {50, 100, 50, 255}) 29 | 30 | // Draw walls 31 | rl::drawCube({-16, 2.5, 0}, 1, 5, 32, { 90, 90, 90, 255}) 32 | rl::drawCube({ 16, 2.5, 0}, 1, 5, 32, { 90, 90, 90, 255}) 33 | rl::drawCube({ 0, 2.5, -16}, 32, 5, 1, {120, 120, 120, 255}) 34 | rl::drawCube({ 0, 2.5, 16}, 32, 5, 1, {120, 120, 120, 255}) 35 | 36 | // Draw columns 37 | for _, cube in cubes { 38 | rl::drawCube(cube.position, 2, cube.height, 2, cube.color) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/3dcam/build_3dcam_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp ../../libumka.so . 4 | cp ../../umka_api.h . 5 | 6 | gcc 3dcam.c -o 3dcam -lumka -lraylib -L$PWD -Wl,-rpath,'$ORIGIN' 7 | -------------------------------------------------------------------------------- /examples/3dcam/build_3dcam_windows_mingw.bat: -------------------------------------------------------------------------------- 1 | copy ..\..\libumka.dll . 2 | copy ..\..\libumka.a . 3 | copy ..\..\umka_api.h . 4 | 5 | gcc 3dcam.c -o 3dcam.exe -lumka -lraylib -L%cd% 6 | -------------------------------------------------------------------------------- /examples/fractal/fractal.um: -------------------------------------------------------------------------------- 1 | // Fractal demo in Umka (adapted from a Wren version by Robert Nystrom) 2 | 3 | fn main() { 4 | const ( 5 | yMin = -0.2 6 | yMax = 0.1 7 | xMin = -1.5 8 | xMax = -1.1 9 | ) 10 | 11 | for yPixel := 0; yPixel < 40; yPixel++ { 12 | y0 := (yPixel / 40.0) * (yMax - yMin) + yMin 13 | 14 | for xPixel := 0; xPixel < 79; xPixel++ { 15 | x0 := (xPixel / 78.0) * (xMax - xMin) + xMin 16 | x, y := x0, y0 17 | pixel := ' ' 18 | 19 | for iter := 0; iter < 80; iter++ { 20 | x, y = x * x - y * y + x0, 2 * x * y + y0 21 | 22 | // Stop if the point escaped 23 | if x * x + y * y > 4 { 24 | const pixels = " .:;+=xX$&" 25 | pixel = pixels[iter / 8] 26 | break 27 | } 28 | } 29 | 30 | printf("%c", pixel) 31 | } 32 | 33 | printf("\n") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/lisp/ev.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | 4 | type Expr* = struct { 5 | atom: str 6 | val: int 7 | car, cdr: ^Expr 8 | } 9 | 10 | 11 | fn _null(x: ^Expr): bool { 12 | return x == null 13 | } 14 | 15 | 16 | fn num(x: ^Expr): bool { 17 | return x != null && x.atom == "" 18 | } 19 | 20 | 21 | fn (e: ^Expr) toStr*(): str { 22 | if e == null { 23 | return "nil" 24 | } else if e.atom == "" { 25 | return "(" + e.car.toStr() + " . " + e.cdr.toStr() + ")" 26 | } else if num(e) { 27 | return std::itoa(e.val) 28 | } 29 | return e.atom 30 | } 31 | 32 | 33 | fn (e: ^Expr) toInt*(): int { 34 | if !num(e) { 35 | exit(1, e.toStr() + " is non-numeric") 36 | } 37 | return e.val 38 | } 39 | 40 | 41 | fn (e: ^Expr) toBool*(): bool { 42 | return e != null 43 | } 44 | 45 | 46 | fn strExpr*(s: str): ^Expr { 47 | return &Expr{s, 0, null, null} 48 | } 49 | 50 | 51 | fn intExpr*(i: int): ^Expr { 52 | return &Expr{"", i, null, null} 53 | } 54 | 55 | 56 | fn boolExpr*(b: bool): ^Expr { 57 | if b {return strExpr("t")} 58 | return null 59 | } 60 | 61 | 62 | // Elementary functions 63 | 64 | fn car*(x: ^Expr): ^Expr { 65 | if x == null { 66 | return null 67 | } else if x.atom != "" { 68 | exit(1, "car() is undefined for atom " + x.toStr()) 69 | } 70 | return x.car 71 | } 72 | 73 | 74 | fn cdr*(x: ^Expr): ^Expr { 75 | if x == null { 76 | return null 77 | } else if x.atom != "" { 78 | exit(1, "cdr() is undefined for atom " + x.toStr()) 79 | } 80 | return x.cdr 81 | } 82 | 83 | 84 | fn cons*(x, y: ^Expr): ^Expr { 85 | return &Expr{"", 0, x, y} 86 | } 87 | 88 | 89 | fn atom*(x: ^Expr): bool { 90 | return x == null || x.atom != "" 91 | } 92 | 93 | 94 | fn eq*(x, y: ^Expr): bool { 95 | if x == null {return y == null} 96 | if y == null {return x == null} 97 | 98 | if !atom(x) || !atom(y) { 99 | exit(1, "eq() is undefined for non-atom(s) (" + x.toStr() + ", " + y.toStr() + ")") 100 | } 101 | 102 | if num(x) && num(y) {return x.val == y.val} 103 | return x.atom == y.atom 104 | } 105 | 106 | 107 | // Arithmetical functions 108 | 109 | fn ne*(x, y: ^Expr): bool {return x.toInt() != y.toInt()} 110 | fn gt*(x, y: ^Expr): bool {return x.toInt() > y.toInt()} 111 | fn ge*(x, y: ^Expr): bool {return x.toInt() >= y.toInt()} 112 | fn lt*(x, y: ^Expr): bool {return x.toInt() < y.toInt()} 113 | fn le*(x, y: ^Expr): bool {return x.toInt() <= y.toInt()} 114 | 115 | fn add*(x, y: ^Expr): ^Expr {return intExpr(x.toInt() + y.toInt())} 116 | fn sub*(x, y: ^Expr): ^Expr {return intExpr(x.toInt() - y.toInt())} 117 | fn mul*(x, y: ^Expr): ^Expr {return intExpr(x.toInt() * y.toInt())} 118 | fn div*(x, y: ^Expr): ^Expr {return intExpr(x.toInt() / y.toInt())} 119 | fn rem*(x, y: ^Expr): ^Expr {return intExpr(x.toInt() % y.toInt())} 120 | 121 | 122 | // Helper functions 123 | 124 | fn eval(e, a: ^Expr): ^Expr 125 | 126 | 127 | fn equal(x, y: ^Expr): bool { 128 | if atom(x) { 129 | if atom(y) { 130 | return eq(x, y) 131 | } else { 132 | return false 133 | } 134 | } else if equal(car(x), car(y)) { 135 | return equal(cdr(x), cdr(y)) 136 | } 137 | return false 138 | } 139 | 140 | 141 | fn pairlis(x, y, a: ^Expr): ^Expr { 142 | if _null(x) {return a} 143 | return cons(cons(car(x), car(y)), pairlis(cdr(x), cdr(y), a)) 144 | } 145 | 146 | 147 | fn assoc(x, a: ^Expr): ^Expr { 148 | if a == null { 149 | exit(1, "No association for " + x.toStr()) 150 | } else if equal(car(car(a)), x) { 151 | return car(a) 152 | } 153 | return assoc(x, cdr(a)) 154 | } 155 | 156 | 157 | fn evcon(c, a: ^Expr): ^Expr { 158 | if eval(car(car(c)), a).toBool() { 159 | return eval(car(cdr(car(c))), a) 160 | } 161 | return evcon(cdr(c), a) 162 | } 163 | 164 | 165 | fn evlis(m, a: ^Expr): ^Expr { 166 | if _null(m) {return null} 167 | return cons(eval(car(m), a), evlis(cdr(m), a)) 168 | } 169 | 170 | 171 | // Universal function (Lisp 1.5 manual, p. 13) 172 | 173 | fn apply(f, x, a: ^Expr): ^Expr { 174 | if atom(f) { 175 | if num(f) { 176 | return cons(f, x) 177 | 178 | } else if eq(f, strExpr("car")) { 179 | return car(car(x)) 180 | } else if eq(f, strExpr("cdr")) { 181 | return cdr(car(x)) 182 | } else if eq(f, strExpr("cons")) { 183 | return cons(car(x), car(cdr(x))) 184 | } else if eq(f, strExpr("atom")) { 185 | return boolExpr(atom(car(x))) 186 | } else if eq(f, strExpr("eq")) { 187 | return boolExpr(eq(car(x), car(cdr(x)))) 188 | 189 | } else if eq(f, strExpr("ne")) { 190 | return boolExpr(ne(car(x), car(cdr(x)))) 191 | } else if eq(f, strExpr("gt")) { 192 | return boolExpr(gt(car(x), car(cdr(x)))) 193 | } else if eq(f, strExpr("ge")) { 194 | return boolExpr(ge(car(x), car(cdr(x)))) 195 | } else if eq(f, strExpr("lt")) { 196 | return boolExpr(lt(car(x), car(cdr(x)))) 197 | } else if eq(f, strExpr("le")) { 198 | return boolExpr(le(car(x), car(cdr(x)))) 199 | 200 | } else if eq(f, strExpr("add")) { 201 | return add(car(x), car(cdr(x))) 202 | } else if eq(f, strExpr("sub")) { 203 | return sub(car(x), car(cdr(x))) 204 | } else if eq(f, strExpr("mul")) { 205 | return mul(car(x), car(cdr(x))) 206 | } else if eq(f, strExpr("div")) { 207 | return div(car(x), car(cdr(x))) 208 | } else if eq(f, strExpr("rem")) { 209 | return rem(car(x), car(cdr(x))) 210 | 211 | } else { 212 | return apply(eval(f, a), x, a) 213 | } 214 | } else if eq(car(f), strExpr("lambda")) { 215 | return eval(car(cdr(cdr(f))), pairlis(car(cdr(f)), x, a)) 216 | } else if eq(car(f), strExpr("label")) { 217 | return apply(car(cdr(cdr(f))), x, cons(cons(car(cdr(f)), car(cdr(cdr(f)))), a)) 218 | } 219 | exit(1, "Illegal function call") 220 | return null 221 | } 222 | 223 | 224 | fn eval(e, a: ^Expr): ^Expr { 225 | if atom(e) { 226 | if num(e) { 227 | return e 228 | } else { 229 | return cdr(assoc(e, a)) 230 | } 231 | } else if atom(car(e)) { 232 | if eq(car(e), strExpr("quote")) { 233 | return car(cdr(e)) 234 | } else if eq(car(e), strExpr("cond")) { 235 | return evcon(cdr(e), a) 236 | } else { 237 | return apply(car(e), evlis(cdr(e), a), a) 238 | } 239 | } 240 | return apply(car(e), evlis(cdr(e), a), a) 241 | 242 | } 243 | 244 | 245 | fn evalquote*(f, x: ^Expr): ^Expr { 246 | return apply(f, x, null) 247 | } 248 | -------------------------------------------------------------------------------- /examples/lisp/lex.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | type ( 4 | TokenKind* = enum { 5 | Null 6 | Atom 7 | LPar 8 | RPar 9 | } 10 | 11 | Token* = struct { 12 | kind: TokenKind 13 | name: str 14 | val: int 15 | } 16 | 17 | Lexer* = struct { 18 | buf: str 19 | pos, size: int 20 | ch: char 21 | tok: Token 22 | } 23 | ) 24 | 25 | 26 | spelling := [4]str{ 27 | "nothing", 28 | "atom", 29 | "(", 30 | ")" 31 | } 32 | 33 | 34 | fn (l: ^Lexer) open*(buf: str) { 35 | l.buf = buf 36 | l.pos = 0 37 | l.size = len(l.buf) 38 | l.ch = ' ' 39 | } 40 | 41 | 42 | fn (l: ^Lexer) getch(): char { 43 | if l.pos >= l.size {return '\0'} 44 | c := l.buf[l.pos] 45 | l.pos++ 46 | return c 47 | } 48 | 49 | 50 | fn (l: ^Lexer) next*() { 51 | const letter = fn(c: char): bool {return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'} 52 | const digit = fn(c: char): bool {return c >= '0' && c <= '9'} 53 | const space = fn(c: char): bool {return c == ' ' || c == '\t' || c == '\n'} 54 | 55 | ch := l.ch 56 | l.tok = Token{.Null, "", 0} 57 | 58 | // Skip spaces 59 | for space(ch) { 60 | ch = l.getch() 61 | } 62 | 63 | // Read string atom 64 | if letter(ch) { 65 | l.tok.kind = .Atom 66 | l.tok.name = "" 67 | for letter(ch) || digit(ch) { 68 | l.tok.name += ch 69 | ch = l.getch() 70 | } 71 | 72 | // Read number 73 | } else if ch == '+' || ch == '-' || digit(ch) { 74 | l.tok.kind = .Atom 75 | l.tok.name = "" 76 | s := "" 77 | if ch == '+' || ch == '-' { 78 | s = ch 79 | ch = l.getch() 80 | } 81 | for digit(ch) { 82 | s += ch 83 | ch = l.getch() 84 | } 85 | l.tok.val = std::atoi(s) 86 | 87 | // Read parentheses 88 | } else if ch == '(' || ch == ')' { 89 | if ch == '(' {l.tok.kind = .LPar} else {l.tok.kind = .RPar} 90 | l.tok.name = ch 91 | ch = l.getch() 92 | 93 | } else if ch != '\0' { 94 | exit(2, "Illegal character " + ch + " (" + std::itoa(int(ch)) + ")") 95 | } 96 | 97 | l.ch = ch 98 | } 99 | 100 | 101 | fn (l: ^Lexer) check*(kind: TokenKind) { 102 | if l.tok.kind != kind { 103 | exit(2, spelling[int(kind)] + " expected but " + spelling[int(l.tok.kind)] + " found") 104 | } 105 | } 106 | 107 | 108 | fn (l: ^Lexer) eat*(kind: TokenKind) { 109 | l.check(kind) 110 | l.next() 111 | } 112 | -------------------------------------------------------------------------------- /examples/lisp/lisp.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "std.um" 3 | "parse.um" 4 | ) 5 | 6 | fn getStr(): str { 7 | s := "" 8 | for true { 9 | c := std::getchar() 10 | if c == '\n' {break} 11 | s += c 12 | } 13 | return s 14 | } 15 | 16 | 17 | fn main() { 18 | printf("Lisp interpreter\n\n") 19 | printf("Examples:\n") 20 | printf(" ((lambda(x y)(cons (car x) y))(quote (a b))(quote (c d)))\n") 21 | printf(" ((label fac(lambda(n)(cond((eq n 0) 1)((quote t)(mul n (fac(sub n 1))))))) 6)\n\n") 22 | 23 | for true { 24 | printf("> ") 25 | input := getStr() 26 | if input == "" {break} 27 | printf("< %s\n\n", parse::execStr(input)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/lisp/parse.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "lex.um" 3 | "ev.um" 4 | ) 5 | 6 | 7 | type Parser* = struct { 8 | lexer: lex::Lexer 9 | } 10 | 11 | 12 | fn (p: ^Parser) parse(): ^ev::Expr { 13 | // Parse list 14 | if p.lexer.tok.kind == .LPar { 15 | p.lexer.next() 16 | 17 | var first, last: ^ev::Expr 18 | for p.lexer.tok.kind == .Atom || p.lexer.tok.kind == .LPar { 19 | e := ev::strExpr("") 20 | e.car = p.parse() 21 | 22 | if first == null { 23 | first = e 24 | last = e 25 | } else { 26 | last.cdr = e 27 | last = e 28 | } 29 | } 30 | p.lexer.eat(.RPar) 31 | return first 32 | } 33 | 34 | // Parse atom 35 | p.lexer.check(.Atom) 36 | res := &ev::Expr{p.lexer.tok.name, p.lexer.tok.val, null, null} 37 | p.lexer.next() 38 | return res 39 | 40 | } 41 | 42 | 43 | fn parseStr*(buf: str): ^ev::Expr { 44 | var p: Parser 45 | p.lexer.open(buf) 46 | p.lexer.next() 47 | return p.parse() 48 | } 49 | 50 | 51 | fn execStr*(buf: str): str { 52 | e := parseStr(buf) 53 | 54 | // Convert expression to a fictitious function call: apply((lambda () e), nil) 55 | lambda := ev::cons(ev::strExpr("lambda"), ev::cons(null, ev::cons(e, null))) 56 | return ev::evalquote(lambda, null).toStr() 57 | } 58 | 59 | -------------------------------------------------------------------------------- /examples/raytracer/raytracer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/examples/raytracer/raytracer.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

The Umka playground

5 | Umka on GitHub 6 |

7 | 8 |

9 | 10 |

11 | 12 | 13 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /projects/libumka.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 96 | 97 | -------------------------------------------------------------------------------- /projects/umka.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 47 | 48 | -------------------------------------------------------------------------------- /projects/umka.workspace: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /resources/fem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/fem.png -------------------------------------------------------------------------------- /resources/lisp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/lisp.png -------------------------------------------------------------------------------- /resources/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 14 | 24 | 31 | 39 | 41 | 43 | 44 | -------------------------------------------------------------------------------- /resources/moneyplease.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/moneyplease.png -------------------------------------------------------------------------------- /resources/os.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/os.png -------------------------------------------------------------------------------- /resources/perf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/perf.png -------------------------------------------------------------------------------- /resources/spacesim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/spacesim.png -------------------------------------------------------------------------------- /resources/stopwar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/stopwar.png -------------------------------------------------------------------------------- /resources/tophat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/tophat.png -------------------------------------------------------------------------------- /resources/tractor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/tractor.png -------------------------------------------------------------------------------- /resources/vdrift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/resources/vdrift.png -------------------------------------------------------------------------------- /run_emscripten.bat: -------------------------------------------------------------------------------- 1 | emcc -O3 -malign-double -fno-strict-aliasing -fvisibility=hidden -DUMKA_STATIC -sSINGLE_FILE -sASYNCIFY -sSTACK_SIZE=5MB -sALLOW_MEMORY_GROWTH -sEXPORTED_FUNCTIONS=_runPlayground -sEXPORTED_RUNTIME_METHODS=ccall,cwrap -Wall -Wno-format-security -o umka.js umka.c umka_api.c umka_common.c umka_compiler.c umka_const.c umka_decl.c umka_expr.c umka_gen.c umka_ident.c umka_lexer.c umka_runtime.c umka_stmt.c umka_types.c umka_vm.c 2 | -------------------------------------------------------------------------------- /run_emscripten_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | emcc -O3 -malign-double -fno-strict-aliasing -fvisibility=hidden -DUMKA_STATIC -sSINGLE_FILE -sASYNCIFY -sSTACK_SIZE=5MB -sALLOW_MEMORY_GROWTH -sEXPORTED_FUNCTIONS=_runPlayground -sEXPORTED_RUNTIME_METHODS=ccall,cwrap -Wall -Wno-format-security -o umka.js umka.c umka_api.c umka_common.c umka_compiler.c umka_const.c umka_decl.c umka_expr.c umka_gen.c umka_ident.c umka_lexer.c umka_runtime.c umka_stmt.c umka_types.c umka_vm.c 3 | -------------------------------------------------------------------------------- /runtime/embed_runtime_linux.sh: -------------------------------------------------------------------------------- 1 | ../umka_linux/umka um2h.um std.um fnc.um mat.um utf8.um 2 | cp umka_runtime_src.h ../src 3 | -------------------------------------------------------------------------------- /runtime/embed_runtime_windows_mingw.bat: -------------------------------------------------------------------------------- 1 | ..\umka_windows_mingw\umka.exe um2h.um std.um fnc.um mat.um utf8.um 2 | copy umka_runtime_src.h ..\src 3 | -------------------------------------------------------------------------------- /runtime/embed_runtime_windows_msvc.bat: -------------------------------------------------------------------------------- 1 | ..\umka_windows_msvc\umka.exe um2h.um std.um fnc.um mat.um utf8.um 2 | copy umka_runtime_src.h ..\src 3 | -------------------------------------------------------------------------------- /runtime/fnc.um: -------------------------------------------------------------------------------- 1 | // Umka functional programming tools 2 | 3 | type Array* = []any 4 | 5 | fn (a: ^Array) transform*(f: fn (x: any): any): Array { 6 | res := make(Array, len(a^)) 7 | for i := 0; i < len(a^); i++ { 8 | res[i] = f(a[i]) 9 | } 10 | return res 11 | } 12 | 13 | fn (a: ^Array) filter*(f: fn (x: any): bool): Array { 14 | res := make(Array, 0) 15 | for i := 0; i < len(a^); i++ { 16 | if f(a[i]) { 17 | res = append(res, a[i]) 18 | } 19 | } 20 | return res 21 | } 22 | 23 | fn (a: ^Array) reduce*(f: fn (x, y: any): any): any { 24 | res := a[0] 25 | for i := 1; i < len(a^); i++ { 26 | res = f(res, a[i]) 27 | } 28 | return res 29 | } 30 | -------------------------------------------------------------------------------- /runtime/mat.um: -------------------------------------------------------------------------------- 1 | // Umka 3D vector/matrix library 2 | 3 | type ( 4 | Vec* = [3]real 5 | Mat* = [3]Vec 6 | ) 7 | 8 | 9 | // Vector operations 10 | 11 | fn (u: ^Vec) add*(v: Vec): Vec {return {u[0] + v[0], u[1] + v[1], u[2] + v[2]}} 12 | fn (u: ^Vec) sub*(v: Vec): Vec {return {u[0] - v[0], u[1] - v[1], u[2] - v[2]}} 13 | fn (u: ^Vec) mul*(a: real): Vec {return {u[0] * a, u[1] * a, u[2] * a}} 14 | fn (u: ^Vec) div*(a: real): Vec {return {u[0] / a, u[1] / a, u[2] / a}} 15 | fn (u: ^Vec) dot*(v: Vec): real {return u[0] * v[0] + u[1] * v[1] + u[2] * v[2]} 16 | fn (u: ^Vec) cross*(v: Vec): Vec {return {u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]}} 17 | fn (u: ^Vec) elementwise*(v: Vec): Vec {return {u[0] * v[0], u[1] * v[1], u[2] * v[2]}} 18 | fn (v: ^Vec) norm*(): real {return sqrt(v.dot(v^))} 19 | fn (v: ^Vec) normalize*(): Vec {return v.div(v.norm())} 20 | 21 | 22 | // Matrix operations 23 | 24 | fn (m: ^Mat) add*(n: Mat): Mat {return {m[0].add(n[0]), m[1].add(n[1]), m[2].add(n[2])}} 25 | fn (m: ^Mat) sub*(n: Mat): Mat {return {m[0].sub(n[0]), m[1].sub(n[1]), m[2].sub(n[2])}} 26 | fn (m: ^Mat) mul*(a: real): Mat {return {m[0].mul(a), m[1].mul(a), m[2].mul(a)}} 27 | fn (m: ^Mat) div*(a: real): Mat {return {m[0].div(a), m[1].div(a), m[2].div(a)}} 28 | fn (m: ^Mat) mulv*(v: Vec): Vec {return {m[0].dot(v), m[1].dot(v), m[2].dot(v)}} 29 | 30 | fn (m: ^Mat) mulm*(n: Mat): Mat { 31 | var res: Mat 32 | for i := 0; i < 3; i++ { 33 | for j := 0; j < 3; j++ { 34 | for k := 0; k < 3; k++ { 35 | res[i][j] += m[i][k] * n[k][j] 36 | } 37 | } 38 | } 39 | return res 40 | } 41 | 42 | fn identity*(): Mat { 43 | var res: Mat 44 | for i := 0; i < 3; i++ { 45 | res[i][i] = 1 46 | } 47 | return res 48 | } 49 | 50 | fn (m: ^Mat) transpose*(): Mat { 51 | var res: Mat 52 | for i := 0; i < 3; i++ { 53 | for j := 0; j < 3; j++ { 54 | res[i][j] = m[j][i] 55 | } 56 | } 57 | return res 58 | } 59 | 60 | fn (m: ^Mat) normalize*(): Mat { 61 | return m.add(m.mulm(identity().sub(m.transpose().mulm(m^))).mul(0.5)) 62 | } 63 | 64 | 65 | // Rotations 66 | 67 | fn (v: ^Vec) toRateMat*(): Mat { 68 | return {{ 0, -v[2], v[1]}, 69 | { v[2], 0, -v[0]}, 70 | {-v[1], v[0], 0 }} 71 | } 72 | 73 | fn (v: ^Vec) toAttMat*(): Mat { 74 | // v = {roll, pitch, yaw} 75 | 76 | sr := sin(v[0]); cr := cos(v[0]) 77 | sp := sin(v[1]); cp := cos(v[1]) 78 | sy := sin(v[2]); cy := cos(v[2]) 79 | 80 | rollMat := Mat{{ 1, 0, 0 }, 81 | { 0, cr, -sr}, 82 | { 0, sr, cr}} 83 | 84 | pitchMat := Mat{{ cp, 0, sp}, 85 | { 0, 1, 0 }, 86 | {-sp, 0, cp}} 87 | 88 | yawMat := Mat{{ cy, -sy, 0 }, 89 | { sy, cy, 0 }, 90 | { 0, 0, 1 }} 91 | 92 | return yawMat.mulm(pitchMat).mulm(rollMat) 93 | } 94 | 95 | fn (m: ^Mat) toAttAngles*(): Vec { 96 | roll := atan2( m[2][1], m[2][2]) 97 | pitch := atan2(-m[2][0], sqrt(m[2][1] * m[2][1] + m[2][2] * m[2][2])) 98 | yaw := atan2( m[1][0], m[0][0]) 99 | return {roll, pitch, yaw} 100 | } -------------------------------------------------------------------------------- /runtime/um2h.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn main() { 4 | std::assert(std::argc() > 1, "No input file(s)") 5 | 6 | fout, err := std::fopen("umka_runtime_src.h", "w") 7 | std::exitif(err) 8 | 9 | fprintf(fout, "#ifndef UMKA_RUNTIME_SRC_H_INCLUDED\n") 10 | fprintf(fout, "#define UMKA_RUNTIME_SRC_H_INCLUDED\n\n") 11 | 12 | fprintf(fout, "// This is an automatically generated file. Do not edit it\n\n") 13 | 14 | fprintf(fout, "static const char *runtimeModuleNames[] = {") 15 | 16 | for argi := 1; argi < std::argc(); argi++ { 17 | fprintf(fout, "\"" + std::argv(argi) + "\"") 18 | if argi != std::argc() - 1 { 19 | fprintf(fout, ", ") 20 | } 21 | } 22 | 23 | fprintf(fout, "};\n\n") 24 | 25 | fprintf(fout, "static const char *runtimeModuleSources[] = {\n") 26 | 27 | for argi := 1; argi < std::argc(); argi++ { 28 | fprintf(fout, "\n// " + std::argv(argi) + "\n\n\"") 29 | 30 | fin, err := std::fopen(std::argv(argi), "rb") 31 | std::exitif(err) 32 | 33 | for !std::feof(fin) { 34 | c := ' ' 35 | fscanf(fin, "%c", &c) 36 | 37 | switch c { 38 | case '\\': fprintf(fout, "\\\\") 39 | case '\'': fprintf(fout, "\\\'") 40 | case '\"': fprintf(fout, "\\\"") 41 | case '\n': fprintf(fout, "\\n\"\n\"") 42 | case '\r': 43 | default: fprintf(fout, "%c", c) 44 | } 45 | } 46 | 47 | if argi != std::argc() - 1 { 48 | fprintf(fout, "\",\n") 49 | } else { 50 | fprintf(fout, "\"\n};\n\n") 51 | } 52 | 53 | std::fclose(fin) 54 | } 55 | 56 | fprintf(fout, "#endif // UMKA_RUNTIME_SRC_H_INCLUDED\n") 57 | 58 | std::fclose(fout) 59 | } -------------------------------------------------------------------------------- /runtime/utf8.um: -------------------------------------------------------------------------------- 1 | // UTF-8 utilities 2 | 3 | type Rune* = int32 4 | 5 | const ( 6 | errRune* = Rune(0xFFFD) 7 | errStr* = "\xEF\xBF\xBD" 8 | ) 9 | 10 | headerOnes := [6]uint8{0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8} 11 | 12 | fn (r: ^Rune) size*(): int { 13 | if r^ <= 0x7F {return 1} 14 | if r^ <= 0x7FF {return 2} 15 | if r^ <= 0xFFFF {return 3} 16 | if r^ <= 0x10FFFF {return 4} 17 | return -1 18 | } 19 | 20 | fn (r: ^Rune) encode*(): str { 21 | size := r.size() 22 | 23 | if size <= 0 {return errStr} 24 | if size == 1 {return str(char(r^))} 25 | 26 | chars := make([]char, size + 1) 27 | 28 | shift := (size - 1) * 6 29 | chars[0] = char(((r^ >> shift & 0xFF) | headerOnes[size]) & 0xFF) 30 | 31 | for i := 1; i < size; i++ { 32 | shift -= 6 33 | chars[i] = char(r^ >> shift & 0x3F | 0x80) 34 | } 35 | 36 | return str(chars) 37 | } 38 | 39 | fn encode*(runes: []Rune): str { 40 | s := "" 41 | for _, r in runes { 42 | s += r.encode() 43 | } 44 | return s 45 | } 46 | 47 | fn decodeRune*(chars: []char, pos: int): Rune { 48 | // Process header byte 49 | header := uint8(chars[pos]) 50 | 51 | if header & 0x80 == 0 { 52 | return Rune(header) // ASCII character 53 | } 54 | 55 | size := 0 56 | 57 | if header & headerOnes[3] == headerOnes[2] { 58 | size = 2 59 | } else if header & headerOnes[4] == headerOnes[3] { 60 | size = 3 61 | } else if header & headerOnes[5] == headerOnes[4] { 62 | size = 4 63 | } 64 | 65 | if size == 0 { 66 | return errRune 67 | } 68 | 69 | shift := (size - 1) * 6 70 | rune := Rune(header & ~headerOnes[size + 1]) << shift 71 | 72 | // Process continuation bytes 73 | for i := 1; i < size; i++ { 74 | if pos + i >= len(chars) { 75 | return errRune 76 | } 77 | 78 | byte := uint8(chars[pos + i]) 79 | if byte & 0xC0 != 0x80 { 80 | return errRune 81 | } 82 | 83 | shift -= 6 84 | rune |= Rune(byte & 0x3F) << shift 85 | } 86 | 87 | return rune 88 | } 89 | 90 | fn decode*(s: str): []Rune { 91 | chars := []char(s) 92 | runes := []Rune{} 93 | 94 | for pos := 0; pos < len(chars) { 95 | rune := decodeRune(chars, pos) 96 | if rune == errRune { 97 | break 98 | } 99 | runes = append(runes, rune) 100 | pos += rune.size() 101 | } 102 | 103 | return runes 104 | } 105 | 106 | fn runeCount*(s: str): int { 107 | chars := []char(s) 108 | count := 0 109 | 110 | for pos := 0; pos < len(chars) { 111 | rune := decodeRune(chars, pos) 112 | if rune == errRune { 113 | break 114 | } 115 | count++ 116 | pos += rune.size() 117 | } 118 | 119 | return count 120 | } 121 | -------------------------------------------------------------------------------- /set_emscripten_paths.bat: -------------------------------------------------------------------------------- 1 | C:\emsdk\emsdk_env.bat 2 | -------------------------------------------------------------------------------- /set_mingw_paths.bat: -------------------------------------------------------------------------------- 1 | set mingw_path=C:\Program Files\CodeBlocks\MinGW 2 | set path=%path%;%mingw_path%\bin;%mingw_path%\lib;%mingw_path%\include 3 | -------------------------------------------------------------------------------- /src/umka.c: -------------------------------------------------------------------------------- 1 | #define __USE_MINGW_ANSI_STDIO 1 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "umka_api.h" 8 | 9 | 10 | enum 11 | { 12 | DEFAULT_STACK_SIZE = 1 * 1024 * 1024, // Slots 13 | MAX_CALL_STACK_DEPTH = 10, 14 | MAX_STR_LENGTH = 256 15 | }; 16 | 17 | 18 | void help(void) 19 | { 20 | printf("%s\n", umkaGetVersion()); 21 | printf("(C) Vasiliy Tereshkov, 2020-2025\n"); 22 | printf("Usage: umka [] []\n"); 23 | printf("Parameters:\n"); 24 | printf(" -stack - Set stack size\n"); 25 | printf(" -asm - Write assembly listing\n"); 26 | printf(" -check - Compile only\n"); 27 | printf(" -warn - Enable warnings\n"); 28 | printf(" -sandbox - Run in sandbox mode\n"); 29 | } 30 | 31 | 32 | bool writeAsmFile(void *umka, const char *mainPath) 33 | { 34 | bool ok = false; 35 | 36 | char *asmFileName = malloc(strlen(mainPath) + 4 + 1); 37 | if (!asmFileName) 38 | fprintf(stderr, "Error: Out of memory\n"); 39 | else 40 | { 41 | sprintf(asmFileName, "%s.asm", mainPath); 42 | const char *asmBuf = umkaAsm(umka); 43 | if (!asmBuf) 44 | fprintf(stderr, "Error: Cannot output assembly listing\n"); 45 | else 46 | { 47 | FILE *asmFile = fopen(asmFileName, "w"); 48 | if (!asmFile) 49 | fprintf(stderr, "Error: Cannot open file %s\n", asmFileName); 50 | else 51 | { 52 | if (fwrite(asmBuf, strlen(asmBuf), 1, asmFile) != 1) 53 | fprintf(stderr, "Error: Cannot write file %s\n", asmFileName); 54 | else 55 | ok = true; 56 | fclose(asmFile); 57 | } 58 | } 59 | free(asmFileName); 60 | } 61 | 62 | return ok; 63 | } 64 | 65 | 66 | void printCompileWarning(UmkaError *warning) 67 | { 68 | fprintf(stderr, "Warning %s (%d, %d): %s\n", warning->fileName, warning->line, warning->pos, warning->msg); 69 | } 70 | 71 | 72 | void printCompileError(void *umka) 73 | { 74 | const UmkaError *error = umkaGetError(umka); 75 | fprintf(stderr, "Error %s (%d, %d): %s\n", error->fileName, error->line, error->pos, error->msg); 76 | } 77 | 78 | 79 | void printRuntimeError(void *umka) 80 | { 81 | const UmkaError *error = umkaGetError(umka); 82 | 83 | if (error->msg[0]) 84 | { 85 | fprintf(stderr, "\nRuntime error %s (%d): %s\n", error->fileName, error->line, error->msg); 86 | fprintf(stderr, "Stack trace:\n"); 87 | 88 | for (int depth = 0; depth < MAX_CALL_STACK_DEPTH; depth++) 89 | { 90 | char fileName[MAX_STR_LENGTH + 1], fnName[MAX_STR_LENGTH + 1]; 91 | int line; 92 | 93 | if (!umkaGetCallStack(umka, depth, MAX_STR_LENGTH + 1, NULL, fileName, fnName, &line)) 94 | break; 95 | 96 | fprintf(stderr, " %s: %s (%d)\n", fnName, fileName, line); 97 | } 98 | } 99 | } 100 | 101 | 102 | #ifdef __EMSCRIPTEN__ 103 | 104 | int runPlayground(const char *fileName, const char *sourceString) 105 | { 106 | void *umka = umkaAlloc(); 107 | bool ok = umkaInit(umka, fileName, sourceString, DEFAULT_STACK_SIZE, NULL, 0, NULL, false, false, printCompileWarning); 108 | if (ok) 109 | ok = umkaCompile(umka); 110 | 111 | if (ok) 112 | { 113 | ok = umkaRun(umka) == 0; 114 | if (ok) 115 | printf("\n"); 116 | else 117 | printRuntimeError(umka); 118 | } 119 | else 120 | printCompileError(umka); 121 | 122 | umkaFree(umka); 123 | return !ok; 124 | } 125 | 126 | #else 127 | 128 | 129 | int main(int argc, char **argv) 130 | { 131 | // Parse interpreter parameters 132 | int stackSize = DEFAULT_STACK_SIZE; 133 | bool writeAsm = false; 134 | bool compileOnly = false; 135 | bool printWarnings = false; 136 | bool isSandbox = false; 137 | 138 | int i = 1; 139 | while (i < argc && argv[i][0] == '-') 140 | { 141 | if (strcmp(argv[i], "-stack") == 0) 142 | { 143 | if (i + 1 == argc) 144 | { 145 | fprintf(stderr, "No stack size\n"); 146 | return 1; 147 | } 148 | 149 | stackSize = strtol(argv[i + 1], NULL, 0); 150 | if (stackSize <= 0) 151 | { 152 | fprintf(stderr, "Illegal stack size\n"); 153 | return 1; 154 | } 155 | 156 | i += 2; 157 | } 158 | else if (strcmp(argv[i], "-asm") == 0) 159 | { 160 | writeAsm = true; 161 | i += 1; 162 | } 163 | else if (strcmp(argv[i], "-check") == 0) 164 | { 165 | compileOnly = true; 166 | i += 1; 167 | } 168 | else if (strcmp(argv[i], "-warn") == 0) 169 | { 170 | printWarnings = true; 171 | i += 1; 172 | } 173 | else if (strcmp(argv[i], "-sandbox") == 0) 174 | { 175 | isSandbox = true; 176 | i += 1; 177 | } 178 | else 179 | break; 180 | } 181 | 182 | // Parse file name 183 | if (i >= argc) 184 | { 185 | help(); 186 | return 1; 187 | } 188 | 189 | void *umka = umkaAlloc(); 190 | bool ok = umkaInit(umka, argv[i], NULL, stackSize, NULL, argc - i, argv + i, !isSandbox, !isSandbox, printWarnings ? printCompileWarning : NULL); 191 | int exitCode = 0; 192 | 193 | if (ok) 194 | ok = umkaCompile(umka); 195 | 196 | if (ok) 197 | { 198 | if (writeAsm) 199 | ok = writeAsmFile(umka, argv[i]); 200 | 201 | if (ok && !compileOnly) 202 | exitCode = umkaRun(umka); 203 | 204 | if (exitCode) 205 | printRuntimeError(umka); 206 | } 207 | else 208 | printCompileError(umka); 209 | 210 | if (!ok) 211 | exitCode = 1; 212 | 213 | umkaFree(umka); 214 | return exitCode; 215 | } 216 | 217 | #endif // EMSCRIPTEN 218 | -------------------------------------------------------------------------------- /src/umka_api.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_API_H_INCLUDED 2 | #define UMKA_API_H_INCLUDED 3 | 4 | 5 | #ifdef _WIN32 6 | #if defined(UMKA_STATIC) 7 | #define UMKA_EXPORT 8 | #define UMKA_IMPORT 9 | #else 10 | #define UMKA_EXPORT __declspec(dllexport) 11 | #define UMKA_IMPORT __declspec(dllimport) 12 | #endif 13 | #else 14 | #define UMKA_EXPORT __attribute__((visibility("default"))) 15 | #define UMKA_IMPORT __attribute__((visibility("default"))) 16 | #endif 17 | 18 | #ifdef UMKA_BUILD 19 | #define UMKA_API UMKA_EXPORT 20 | #else 21 | #define UMKA_API UMKA_IMPORT 22 | #endif 23 | 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | #if defined(__cplusplus) 31 | extern "C" { 32 | #endif 33 | 34 | 35 | typedef union 36 | { 37 | int64_t intVal; 38 | uint64_t uintVal; 39 | void *ptrVal; 40 | double realVal; 41 | float real32Val; 42 | } UmkaStackSlot; 43 | 44 | 45 | typedef struct 46 | { 47 | int64_t entryOffset; 48 | UmkaStackSlot *params; 49 | UmkaStackSlot *result; 50 | } UmkaFuncContext; 51 | 52 | 53 | typedef void (*UmkaExternFunc)(UmkaStackSlot *params, UmkaStackSlot *result); 54 | 55 | 56 | typedef enum 57 | { 58 | UMKA_HOOK_CALL, 59 | UMKA_HOOK_RETURN, 60 | } UmkaHookEvent; 61 | 62 | 63 | typedef void (*UmkaHookFunc)(const char *fileName, const char *funcName, int line); 64 | 65 | 66 | #define UmkaDynArray(T) struct \ 67 | { \ 68 | void *internal; \ 69 | int64_t itemSize; \ 70 | T *data; \ 71 | } 72 | 73 | 74 | typedef struct 75 | { 76 | void *internal1; 77 | void *internal2; 78 | } UmkaMap; 79 | 80 | 81 | typedef struct 82 | { 83 | void *data; 84 | void *type; 85 | } UmkaAny; 86 | 87 | 88 | typedef struct 89 | { 90 | int64_t entryOffset; 91 | UmkaAny upvalue; 92 | } UmkaClosure; 93 | 94 | 95 | typedef struct 96 | { 97 | const char *fileName; 98 | const char *fnName; 99 | int line, pos, code; 100 | const char *msg; 101 | } UmkaError; 102 | 103 | 104 | typedef void (*UmkaWarningCallback)(UmkaError *warning); 105 | 106 | 107 | typedef struct 108 | { 109 | int64_t numParams; 110 | int64_t numResultParams; 111 | int64_t numParamSlots; 112 | int64_t firstSlotIndex[]; 113 | } UmkaExternalCallParamLayout; 114 | 115 | 116 | typedef void *(*UmkaAlloc) (void); 117 | typedef bool (*UmkaInit) (void *umka, const char *fileName, const char *sourceString, int stackSize, void *reserved, int argc, char **argv, bool fileSystemEnabled, bool implLibsEnabled, UmkaWarningCallback warningCallback); 118 | typedef bool (*UmkaCompile) (void *umka); 119 | typedef int (*UmkaRun) (void *umka); 120 | typedef int (*UmkaCall) (void *umka, UmkaFuncContext *fn); 121 | typedef void (*UmkaFree) (void *umka); 122 | typedef UmkaError *(*UmkaGetError) (void *umka); 123 | typedef bool (*UmkaAlive) (void *umka); 124 | typedef char *(*UmkaAsm) (void *umka); 125 | typedef bool (*UmkaAddModule) (void *umka, const char *fileName, const char *sourceString); 126 | typedef bool (*UmkaAddFunc) (void *umka, const char *name, UmkaExternFunc func); 127 | typedef bool (*UmkaGetFunc) (void *umka, const char *moduleName, const char *fnName, UmkaFuncContext *fn); 128 | typedef bool (*UmkaGetCallStack) (void *umka, int depth, int nameSize, int *offset, char *fileName, char *fnName, int *line); 129 | typedef void (*UmkaSetHook) (void *umka, UmkaHookEvent event, UmkaHookFunc hook); 130 | typedef void *(*UmkaAllocData) (void *umka, int size, UmkaExternFunc onFree); 131 | typedef void (*UmkaIncRef) (void *umka, void *ptr); 132 | typedef void (*UmkaDecRef) (void *umka, void *ptr); 133 | typedef void *(*UmkaGetMapItem) (void *umka, UmkaMap *map, UmkaStackSlot key); 134 | typedef char *(*UmkaMakeStr) (void *umka, const char *str); 135 | typedef int (*UmkaGetStrLen) (const char *str); 136 | typedef void (*UmkaMakeDynArray) (void *umka, void *array, void *type, int len); 137 | typedef int (*UmkaGetDynArrayLen) (const void *array); 138 | typedef const char *(*UmkaGetVersion) (void); 139 | typedef int64_t (*UmkaGetMemUsage) (void *umka); 140 | typedef void (*UmkaMakeFuncContext) (void *umka, void *closureType, int entryOffset, UmkaFuncContext *fn); 141 | typedef UmkaStackSlot *(*UmkaGetParam)(UmkaStackSlot *params, int index); 142 | typedef UmkaAny *(*UmkaGetUpvalue) (UmkaStackSlot *params); 143 | typedef UmkaStackSlot *(*UmkaGetResult)(UmkaStackSlot *params, UmkaStackSlot *result); 144 | 145 | 146 | typedef struct 147 | { 148 | UmkaAlloc umkaAlloc; 149 | UmkaInit umkaInit; 150 | UmkaCompile umkaCompile; 151 | UmkaRun umkaRun; 152 | UmkaCall umkaCall; 153 | UmkaFree umkaFree; 154 | UmkaGetError umkaGetError; 155 | UmkaAlive umkaAlive; 156 | UmkaAsm umkaAsm; 157 | UmkaAddModule umkaAddModule; 158 | UmkaAddFunc umkaAddFunc; 159 | UmkaGetFunc umkaGetFunc; 160 | UmkaGetCallStack umkaGetCallStack; 161 | UmkaSetHook umkaSetHook; 162 | UmkaAllocData umkaAllocData; 163 | UmkaIncRef umkaIncRef; 164 | UmkaDecRef umkaDecRef; 165 | UmkaGetMapItem umkaGetMapItem; 166 | UmkaMakeStr umkaMakeStr; 167 | UmkaGetStrLen umkaGetStrLen; 168 | UmkaMakeDynArray umkaMakeDynArray; 169 | UmkaGetDynArrayLen umkaGetDynArrayLen; 170 | UmkaGetVersion umkaGetVersion; 171 | UmkaGetMemUsage umkaGetMemUsage; 172 | UmkaMakeFuncContext umkaMakeFuncContext; 173 | UmkaGetParam umkaGetParam; 174 | UmkaGetUpvalue umkaGetUpvalue; 175 | UmkaGetResult umkaGetResult; 176 | } UmkaAPI; 177 | 178 | 179 | UMKA_API void *umkaAlloc (void); 180 | UMKA_API bool umkaInit (void *umka, const char *fileName, const char *sourceString, int stackSize, void *reserved, int argc, char **argv, bool fileSystemEnabled, bool implLibsEnabled, UmkaWarningCallback warningCallback); 181 | UMKA_API bool umkaCompile (void *umka); 182 | UMKA_API int umkaRun (void *umka); 183 | UMKA_API int umkaCall (void *umka, UmkaFuncContext *fn); 184 | UMKA_API void umkaFree (void *umka); 185 | UMKA_API UmkaError *umkaGetError (void *umka); 186 | UMKA_API bool umkaAlive (void *umka); 187 | UMKA_API char *umkaAsm (void *umka); 188 | UMKA_API bool umkaAddModule (void *umka, const char *fileName, const char *sourceString); 189 | UMKA_API bool umkaAddFunc (void *umka, const char *name, UmkaExternFunc func); 190 | UMKA_API bool umkaGetFunc (void *umka, const char *moduleName, const char *fnName, UmkaFuncContext *fn); 191 | UMKA_API bool umkaGetCallStack (void *umka, int depth, int nameSize, int *offset, char *fileName, char *fnName, int *line); 192 | UMKA_API void umkaSetHook (void *umka, UmkaHookEvent event, UmkaHookFunc hook); 193 | UMKA_API void *umkaAllocData (void *umka, int size, UmkaExternFunc onFree); 194 | UMKA_API void umkaIncRef (void *umka, void *ptr); 195 | UMKA_API void umkaDecRef (void *umka, void *ptr); 196 | UMKA_API void *umkaGetMapItem (void *umka, UmkaMap *map, UmkaStackSlot key); 197 | UMKA_API char *umkaMakeStr (void *umka, const char *str); 198 | UMKA_API int umkaGetStrLen (const char *str); 199 | UMKA_API void umkaMakeDynArray (void *umka, void *array, void *type, int len); 200 | UMKA_API int umkaGetDynArrayLen (const void *array); 201 | UMKA_API const char *umkaGetVersion (void); 202 | UMKA_API int64_t umkaGetMemUsage (void *umka); 203 | UMKA_API void umkaMakeFuncContext (void *umka, void *closureType, int entryOffset, UmkaFuncContext *fn); 204 | UMKA_API UmkaStackSlot *umkaGetParam(UmkaStackSlot *params, int index); 205 | UMKA_API UmkaAny *umkaGetUpvalue (UmkaStackSlot *params); 206 | UMKA_API UmkaStackSlot *umkaGetResult(UmkaStackSlot *params, UmkaStackSlot *result); 207 | 208 | 209 | static inline UmkaAPI *umkaGetAPI(void *umka) 210 | { 211 | return (UmkaAPI *)umka; 212 | } 213 | 214 | 215 | static inline void *umkaGetInstance(UmkaStackSlot *result) 216 | { 217 | return result->ptrVal; 218 | } 219 | 220 | 221 | #if defined(__cplusplus) 222 | } 223 | #endif 224 | 225 | #endif // UMKA_API_H_INCLUDED 226 | -------------------------------------------------------------------------------- /src/umka_common.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_COMMON_H_INCLUDED 2 | #define UMKA_COMMON_H_INCLUDED 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | enum 11 | { 12 | DEFAULT_STR_LEN = 255, 13 | MAX_IDENT_LEN = DEFAULT_STR_LEN, 14 | MAX_IDENTS_IN_LIST = 256, 15 | MAX_MODULES = 1024, 16 | MAX_PARAMS = 16, 17 | MAX_BLOCK_NESTING = 100, 18 | MAX_GOTOS = 100, 19 | }; 20 | 21 | 22 | enum 23 | { 24 | MAP_NODE_FIELD_LEN = 0, 25 | MAP_NODE_FIELD_KEY = 1, 26 | MAP_NODE_FIELD_DATA = 2, 27 | MAP_NODE_FIELD_LEFT = 3, 28 | MAP_NODE_FIELD_RIGHT = 4, 29 | }; 30 | 31 | 32 | typedef struct 33 | { 34 | int64_t len, capacity; 35 | } StrDimensions; 36 | 37 | 38 | typedef StrDimensions DynArrayDimensions; 39 | 40 | 41 | typedef struct 42 | { 43 | // Must have 8 byte alignment 44 | const struct tagType *type; 45 | int64_t itemSize; // Duplicates information contained in type, but useful for better performance 46 | void *data; // Allocated chunk should start at (char *)data - sizeof(DynArrayDimensions) 47 | } DynArray; 48 | 49 | 50 | typedef struct 51 | { 52 | // The C equivalent of the Umka interface type 53 | void *self; 54 | const struct tagType *selfType; 55 | // Methods are omitted - do not use sizeof() for non-empty interfaces 56 | } Interface; 57 | 58 | 59 | typedef struct 60 | { 61 | // The C equivalent of the Umka closure type 62 | int64_t entryOffset; 63 | Interface upvalue; // No methods - equivalent to "any" 64 | } Closure; 65 | 66 | 67 | typedef struct tagMapNode 68 | { 69 | // The C equivalent of the Umka map base type 70 | int64_t len; // Non-zero for the root node only 71 | void *key, *data; 72 | struct tagMapNode *left, *right; 73 | } MapNode; 74 | 75 | 76 | typedef struct 77 | { 78 | // Must have 8 byte alignment 79 | const struct tagType *type; 80 | MapNode *root; 81 | } Map; 82 | 83 | 84 | typedef struct 85 | { 86 | const char *fileName; 87 | const char *fnName; 88 | int line; 89 | } DebugInfo; 90 | 91 | 92 | typedef void (*WarningCallback)(void * /*UmkaError*/ warning); 93 | 94 | 95 | typedef struct // Must be identical to UmkaError 96 | { 97 | const char *fileName; 98 | const char *fnName; 99 | int line, pos, code; 100 | const char *msg; 101 | } ErrorReport; 102 | 103 | 104 | typedef struct 105 | { 106 | void (*handler)(void *context, const char *format, ...); 107 | void (*runtimeHandler)(void *context, int code, const char *format, ...); 108 | void (*warningHandler)(void *context, const DebugInfo *debug, const char *format, ...); 109 | WarningCallback warningCallback; 110 | void *context; 111 | jmp_buf jumper; 112 | int jumperNesting; 113 | ErrorReport report; 114 | } Error; 115 | 116 | 117 | typedef struct tagStorageChunk 118 | { 119 | struct tagStorageChunk *prev, *next; 120 | int64_t size; 121 | char data[]; 122 | } StorageChunk; 123 | 124 | 125 | typedef struct 126 | { 127 | StorageChunk *first; 128 | Error *error; 129 | } Storage; 130 | 131 | 132 | typedef struct 133 | { 134 | char path[DEFAULT_STR_LEN + 1], folder[DEFAULT_STR_LEN + 1], name[DEFAULT_STR_LEN + 1]; 135 | unsigned int pathHash; 136 | void *implLib; 137 | char *importAlias[MAX_MODULES]; 138 | bool isCompiled; 139 | } Module; 140 | 141 | 142 | typedef struct 143 | { 144 | char path[DEFAULT_STR_LEN + 1], folder[DEFAULT_STR_LEN + 1], name[DEFAULT_STR_LEN + 1]; 145 | unsigned int pathHash; 146 | char *source; 147 | bool trusted; 148 | } ModuleSource; 149 | 150 | 151 | typedef struct 152 | { 153 | Module *module[MAX_MODULES]; 154 | const ModuleSource *moduleSource[MAX_MODULES]; 155 | int numModules, numModuleSources; 156 | char curFolder[DEFAULT_STR_LEN + 1]; 157 | bool implLibsEnabled; 158 | Storage *storage; 159 | Error *error; 160 | } Modules; 161 | 162 | 163 | typedef struct 164 | { 165 | int block; 166 | const struct tagIdent *fn; 167 | int localVarSize; // For function blocks only 168 | bool hasReturn; 169 | bool hasUpvalues; 170 | } BlockStackSlot; 171 | 172 | 173 | typedef struct 174 | { 175 | BlockStackSlot item[MAX_BLOCK_NESTING]; 176 | int numBlocks, top; 177 | int module; 178 | Error *error; 179 | } Blocks; 180 | 181 | 182 | typedef struct tagExternal 183 | { 184 | char name[DEFAULT_STR_LEN + 1]; 185 | unsigned int hash; 186 | void *entry; 187 | bool resolved, resolveInTrusted; 188 | struct tagExternal *next; 189 | } External; 190 | 191 | 192 | typedef struct 193 | { 194 | External *first; 195 | Storage *storage; 196 | } Externals; 197 | 198 | 199 | typedef struct 200 | { 201 | int64_t numParams; 202 | int64_t numResultParams; 203 | int64_t numParamSlots; 204 | int64_t firstSlotIndex[]; 205 | } ParamLayout; 206 | 207 | 208 | typedef struct 209 | { 210 | const ParamLayout *paramLayout; 211 | int64_t localVarSlots; 212 | } ParamAndLocalVarLayout; 213 | 214 | 215 | void errorReportInit(ErrorReport *report, Storage *storage, const char *fileName, const char *fnName, int line, int pos, int code, const char *format, va_list args); 216 | 217 | void storageInit (Storage *storage, Error *error); 218 | void storageFree (Storage *storage); 219 | void *storageAdd (Storage *storage, int64_t size); 220 | char *storageAddStr (Storage *storage, int64_t len); 221 | DynArray *storageAddDynArray (Storage *storage, const struct tagType *type, int64_t len); 222 | void storageRemove (Storage *storage, void *data); 223 | void *storageRealloc (Storage *storage, void *data, int64_t size); 224 | 225 | void moduleInit (Modules *modules, Storage *storage, bool implLibsEnabled, Error *error); 226 | void moduleFree (Modules *modules); 227 | void moduleNameFromPath (const Modules *modules, const char *path, char *folder, char *name, int size); 228 | int moduleFind (const Modules *modules, const char *path); 229 | int moduleFindImported (const Modules *modules, const Blocks *blocks, const char *alias); 230 | int moduleAdd (Modules *modules, const char *path); 231 | const ModuleSource *moduleFindSource(const Modules *modules, const char *path); 232 | void moduleAddSource (Modules *modules, const char *path, const char *source, bool trusted); 233 | void *moduleGetImplLibFunc (const Module *module, const char *name); 234 | char *moduleCurFolder (char *buf, int size); 235 | bool modulePathIsAbsolute (const char *path); 236 | bool moduleRegularizePath (const Modules *modules, const char *path, const char *curFolder, char *regularizedPath, int size); 237 | void moduleAssertRegularizePath(const Modules *modules, const char *path, const char *curFolder, char *regularizedPath, int size); 238 | 239 | void blocksInit (Blocks *blocks, Error *error); 240 | void blocksEnterFn(Blocks *blocks, const struct tagIdent *fn, bool hasUpvalues); 241 | void blocksEnter (Blocks *blocks); 242 | void blocksReenter(Blocks *blocks); 243 | void blocksLeave (Blocks *blocks); 244 | int blocksCurrent(const Blocks *blocks); 245 | 246 | void externalInit (Externals *externals, Storage *storage); 247 | External *externalFind (const Externals *externals, const char *name); 248 | External *externalAdd (Externals *externals, const char *name, void *entry, bool resolveInTrusted); 249 | 250 | 251 | static inline unsigned int hash(const char *str) 252 | { 253 | // djb2 hash 254 | unsigned int hash = 5381; 255 | char ch; 256 | 257 | while ((ch = *str++)) 258 | hash = ((hash << 5) + hash) + ch; 259 | 260 | return hash; 261 | } 262 | 263 | 264 | static inline int64_t nonneg(int64_t size) 265 | { 266 | return (size > 0) ? size : 0; 267 | } 268 | 269 | 270 | static inline int64_t align(int64_t size, int64_t alignment) 271 | { 272 | return ((size + (alignment - 1)) / alignment) * alignment; 273 | } 274 | 275 | 276 | static inline StrDimensions *getStrDims(const char *str) 277 | { 278 | return (StrDimensions *)(str - sizeof(StrDimensions)); 279 | } 280 | 281 | 282 | static inline DynArrayDimensions *getDims(const DynArray *array) 283 | { 284 | return (DynArrayDimensions *)((char *)array->data - sizeof(DynArrayDimensions)); 285 | } 286 | 287 | 288 | #endif // UMKA_COMMON_H_INCLUDED 289 | -------------------------------------------------------------------------------- /src/umka_compiler.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_COMPILER_H_INCLUDED 2 | #define UMKA_COMPILER_H_INCLUDED 3 | 4 | #include "umka_common.h" 5 | #include "umka_lexer.h" 6 | #include "umka_types.h" 7 | #include "umka_vm.h" 8 | #include "umka_gen.h" 9 | #include "umka_ident.h" 10 | #include "umka_const.h" 11 | #include "umka_runtime.h" 12 | #include "umka_api.h" 13 | 14 | 15 | typedef struct 16 | { 17 | UmkaAPI api; // Must be the first field 18 | 19 | Storage storage; 20 | Modules modules; 21 | Blocks blocks; 22 | Externals externals; 23 | Lexer lex; 24 | Types types; 25 | Idents idents; 26 | Consts consts; 27 | CodeGen gen; 28 | VM vm; 29 | DebugInfo debug; 30 | Error error; 31 | 32 | // Pointers to built-in types 33 | const Type 34 | *voidType, 35 | *nullType, 36 | *int8Type, *int16Type, *int32Type, *intType, 37 | *uint8Type, *uint16Type, *uint32Type, *uintType, 38 | *boolType, 39 | *charType, 40 | *real32Type, *realType, 41 | *strType, 42 | *fiberType, 43 | *ptrVoidType, *ptrNullType, 44 | *anyType, 45 | *fileType; 46 | 47 | // Command-line arguments 48 | int argc; 49 | char **argv; 50 | 51 | // Original codepages (Windows only) 52 | unsigned int originalInputCodepage, originalOutputCodepage; 53 | 54 | } Compiler; 55 | 56 | 57 | void compilerInit (Compiler *comp, const char *fileName, const char *sourceString, int stackSize, int argc, char **argv, bool fileSystemEnabled, bool implLibsEnabled); 58 | void compilerFree (Compiler *comp); 59 | void compilerCompile (Compiler *comp); 60 | void compilerRun (Compiler *comp); 61 | void compilerCall (Compiler *comp, FuncContext *fn); 62 | char *compilerAsm (Compiler *comp); 63 | bool compilerAddModule (Compiler *comp, const char *fileName, const char *sourceString); 64 | bool compilerAddFunc (Compiler *comp, const char *name, ExternFunc func); 65 | bool compilerGetFunc (Compiler *comp, const char *moduleName, const char *funcName, FuncContext *fn); 66 | void compilerMakeFuncContext (Compiler *comp, const Type *fnType, int entryOffset, FuncContext *fn); 67 | 68 | #endif // UMKA_COMPILER_H_INCLUDED 69 | -------------------------------------------------------------------------------- /src/umka_const.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_CONST_H_INCLUDED 2 | #define UMKA_CONST_H_INCLUDED 3 | 4 | #include "umka_lexer.h" 5 | #include "umka_vm.h" 6 | 7 | 8 | typedef struct 9 | { 10 | Error *error; 11 | } Consts; 12 | 13 | 14 | typedef struct 15 | { 16 | Storage *storage; 17 | Const *data; 18 | const Type *type; 19 | int len, capacity; 20 | } ConstArray; 21 | 22 | 23 | void constInit(Consts *consts, Error *error); 24 | void constZero(void *lhs, int size); 25 | void constDeref(const Consts *consts, Const *constant, TypeKind typeKind); 26 | void constAssign(const Consts *consts, void *lhs, const Const *rhs, TypeKind typeKind, int size); 27 | void constUnary(const Consts *consts, Const *arg, TokenKind tokKind, TypeKind typeKind); 28 | void constBinary(const Consts *consts, Const *lhs, const Const *rhs, TokenKind tokKind, TypeKind typeKind); 29 | void constCallBuiltin(const Consts *consts, Const *arg, const Const *arg2, TypeKind argTypeKind, BuiltinFunc builtinVal); 30 | 31 | void constArrayAlloc(ConstArray *array, Storage *storage, const Type *type); 32 | void constArrayAppend(ConstArray *array, Const val); 33 | int constArrayFind(const Consts *consts, const ConstArray *array, Const val); 34 | int constArrayFindEquivalentType(const Consts *consts, const ConstArray *array, Const val); 35 | void constArrayFree(ConstArray *array); 36 | 37 | 38 | #endif // UMKA_CONST_H_INCLUDED 39 | -------------------------------------------------------------------------------- /src/umka_decl.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_DECL_H_INCLUDED 2 | #define UMKA_DECL_H_INCLUDED 3 | 4 | #include "umka_compiler.h" 5 | 6 | 7 | const Type *parseType(Compiler *comp, const Ident *ident); 8 | void parseShortVarDecl(Compiler *comp); 9 | void parseDecl(Compiler *comp); 10 | void parseProgram(Compiler *comp); 11 | 12 | 13 | #endif // UMKA_DECL_H_INCLUDED 14 | -------------------------------------------------------------------------------- /src/umka_expr.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_EXPR_H_INCLUDED 2 | #define UMKA_EXPR_H_INCLUDED 3 | 4 | #include "umka_compiler.h" 5 | 6 | 7 | void doPushConst (Compiler *comp, const Type *type, const Const *constant); 8 | void doPushVarPtr (Compiler *comp, const Ident *ident); 9 | void doCopyResultToTempVar (Compiler *comp, const Type *type); 10 | bool doTryRemoveCopyResultToTempVar (Compiler *comp); 11 | void doImplicitTypeConv (Compiler *comp, const Type *dest, const Type **src, Const *constant); 12 | void doAssertImplicitTypeConv (Compiler *comp, const Type *dest, const Type **src, Const *constant); 13 | void doExplicitTypeConv (Compiler *comp, const Type *dest, const Type **src, Const *constant); 14 | void doApplyOperator (Compiler *comp, const Type **type, const Type **rightType, Const *constant, Const *rightConstant, TokenKind op, bool apply, bool convertLhs); 15 | 16 | const Ident *parseQualIdent (Compiler *comp); 17 | void parseDesignatorList (Compiler *comp, const Type **type, Const *constant, bool *isVar, bool *isCall, bool *isCompLit); 18 | void parseExpr (Compiler *comp, const Type **type, Const *constant); 19 | void parseExprList (Compiler *comp, const Type **type, Const *constant); 20 | 21 | 22 | #endif // UMKA_EXPR_H_INCLUDED 23 | -------------------------------------------------------------------------------- /src/umka_gen.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_GEN_H_INCLUDED 2 | #define UMKA_GEN_H_INCLUDED 3 | 4 | #include "umka_common.h" 5 | #include "umka_vm.h" 6 | 7 | 8 | typedef struct 9 | { 10 | int start[MAX_GOTOS]; 11 | int numGotos; 12 | int block; 13 | const Type *returnType; 14 | } Gotos; 15 | 16 | 17 | typedef enum 18 | { 19 | GEN_NOTIFICATION_NONE, 20 | GEN_NOTIFICATION_COPY_RESULT_TO_TEMP_VAR 21 | } GenNotificationKind; 22 | 23 | 24 | typedef struct 25 | { 26 | GenNotificationKind kind; 27 | int ip; 28 | } GenNotification; 29 | 30 | 31 | typedef struct 32 | { 33 | Instruction *code; 34 | int ip, capacity; 35 | int stack[MAX_BLOCK_NESTING]; 36 | int top; 37 | int lastJump; 38 | Gotos *breaks, *continues, *returns; 39 | Storage *storage; 40 | DebugInfo *debug, *debugPerInstr; 41 | GenNotification lastNotification; 42 | Error *error; 43 | } CodeGen; 44 | 45 | 46 | void genInit(CodeGen *gen, Storage *storage, DebugInfo *debug, Error *error); 47 | 48 | // Atomic VM instructions 49 | 50 | void genNop(CodeGen *gen); 51 | 52 | void genPushIntConst (CodeGen *gen, int64_t intVal); 53 | void genPushUIntConst (CodeGen *gen, uint64_t uintVal); 54 | void genPushRealConst (CodeGen *gen, double realVal); 55 | void genPushGlobalPtr (CodeGen *gen, void *ptrVal); 56 | void genPushLocalPtr (CodeGen *gen, int offset); 57 | void genPushLocalPtrZero(CodeGen *gen, int offset, int size); 58 | void genPushLocal (CodeGen *gen, TypeKind typeKind, int offset); 59 | void genPushReg (CodeGen *gen, RegisterIndex regIndex); 60 | void genPushStruct (CodeGen *gen, int size); 61 | void genPushUpvalue (CodeGen *gen); 62 | void genPushZero (CodeGen *gen, int slots); 63 | 64 | void genPop (CodeGen *gen); 65 | void genPopReg(CodeGen *gen, RegisterIndex regIndex); 66 | void genDup (CodeGen *gen); 67 | void genSwap (CodeGen *gen); 68 | void genZero (CodeGen *gen, int size); 69 | 70 | void genDeref (CodeGen *gen, TypeKind typeKind); 71 | void genAssign (CodeGen *gen, TypeKind typeKind, int structSize); 72 | void genSwapAssign (CodeGen *gen, TypeKind typeKind, int structSize); 73 | void genAssignParam (CodeGen *gen, TypeKind typeKind, int structSize); 74 | 75 | void genChangeRefCnt (CodeGen *gen, TokenKind tokKind, const Type *type); 76 | void genChangeRefCntGlobal (CodeGen *gen, TokenKind tokKind, void *ptrVal, const Type *type); 77 | void genChangeRefCntLocal (CodeGen *gen, TokenKind tokKind, int offset, const Type *type); 78 | void genChangeRefCntAssign (CodeGen *gen, const Type *type); 79 | void genSwapChangeRefCntAssign (CodeGen *gen, const Type *type); 80 | void genChangeLeftRefCntAssign (CodeGen *gen, const Type *type); 81 | 82 | void genUnary (CodeGen *gen, TokenKind tokKind, TypeKind typeKind); 83 | void genBinary(CodeGen *gen, TokenKind tokKind, TypeKind typeKind, int structSize); 84 | 85 | void genGetArrayPtr (CodeGen *gen, int itemSize, int len); 86 | void genGetDynArrayPtr(CodeGen *gen); 87 | void genGetMapPtr (CodeGen *gen, const Type *mapType); 88 | void genGetFieldPtr (CodeGen *gen, int fieldOffset); 89 | 90 | void genAssertType (CodeGen *gen, const Type *type); 91 | void genAssertRange (CodeGen *gen, TypeKind destTypeKind, const Type *srcType); 92 | 93 | void genWeakenPtr (CodeGen *gen); 94 | void genStrengthenPtr(CodeGen *gen); 95 | 96 | void genGoto (CodeGen *gen, int dest); 97 | void genGotoIf (CodeGen *gen, int dest); 98 | void genGotoIfNot (CodeGen *gen, int dest); 99 | 100 | void genCall (CodeGen *gen, int entry); 101 | void genCallIndirect (CodeGen *gen, int paramSlots); 102 | void genCallExtern (CodeGen *gen, void *entry); 103 | void genCallBuiltin (CodeGen *gen, TypeKind typeKind, BuiltinFunc builtin); 104 | void genCallTypedBuiltin (CodeGen *gen, const Type *type, BuiltinFunc builtin); 105 | void genReturn (CodeGen *gen, int paramSlots); 106 | 107 | void genEnterFrame(CodeGen *gen, const ParamAndLocalVarLayout *layout); 108 | void genLeaveFrame(CodeGen *gen); 109 | 110 | void genHalt(CodeGen *gen); 111 | 112 | // Compound VM instructions 113 | 114 | void genGoFromTo (CodeGen *gen, int start, int dest); 115 | void genGoFromToIf (CodeGen *gen, int start, int dest); 116 | 117 | void genIfCondEpilog(CodeGen *gen); 118 | void genIfEpilog (CodeGen *gen); 119 | void genElseProlog (CodeGen *gen); 120 | void genIfElseEpilog(CodeGen *gen); 121 | 122 | void genSwitchCondEpilog (CodeGen *gen); 123 | void genCaseConstantCheck (CodeGen *gen, Const *constant); 124 | void genCaseBlockProlog (CodeGen *gen, int numCaseConstants); 125 | void genCaseBlockEpilog (CodeGen *gen); 126 | void genSwitchEpilog (CodeGen *gen, int numCases); 127 | 128 | void genWhileCondProlog(CodeGen *gen); 129 | void genWhileCondEpilog(CodeGen *gen); 130 | void genWhileEpilog (CodeGen *gen); 131 | 132 | void genForCondProlog (CodeGen *gen); 133 | void genForCondEpilog (CodeGen *gen); 134 | void genForPostStmtEpilog(CodeGen *gen); 135 | void genForEpilog (CodeGen *gen); 136 | 137 | void genShortCircuitProlog(CodeGen *gen); 138 | void genShortCircuitEpilog(CodeGen *gen, TokenKind op); 139 | 140 | void genEnterFrameStub (CodeGen *gen); 141 | void genLeaveFrameFixup(CodeGen *gen, const ParamAndLocalVarLayout *layout); 142 | 143 | void genEntryPoint(CodeGen *gen, int start); 144 | 145 | int genTryRemoveImmediateEntryPoint(CodeGen *gen); 146 | 147 | void genGotosProlog (CodeGen *gen, Gotos *gotos, int block); 148 | void genGotosAddStub(CodeGen *gen, Gotos *gotos); 149 | void genGotosEpilog (CodeGen *gen, Gotos *gotos); 150 | 151 | void genCopyResultToTempVar(CodeGen *gen, const Type *type, int offset); 152 | int genTryRemoveCopyResultToTempVar(CodeGen *gen); 153 | 154 | int genAsm(CodeGen *gen, char *buf, int size); 155 | 156 | #endif // UMKA_GEN_H_INCLUDED 157 | -------------------------------------------------------------------------------- /src/umka_ident.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_IDENT_H_INCLUDED 2 | #define UMKA_IDENT_H_INCLUDED 3 | 4 | #include "umka_common.h" 5 | #include "umka_vm.h" 6 | 7 | 8 | typedef enum 9 | { 10 | // Built-in functions are treated specially, all other functions are either constants or variables of "fn" type 11 | IDENT_CONST, 12 | IDENT_VAR, 13 | IDENT_TYPE, 14 | IDENT_BUILTIN_FN, 15 | IDENT_MODULE 16 | } IdentKind; 17 | 18 | 19 | typedef struct tagIdent 20 | { 21 | IdentKind kind; 22 | IdentName name; 23 | unsigned int hash; 24 | const Type *type; 25 | int module, block; // Place of definition (global identifiers are in block 0) 26 | bool exported, globallyAllocated, used, temporary; 27 | int prototypeOffset; // For function prototypes 28 | union 29 | { 30 | BuiltinFunc builtin; // For built-in functions 31 | void *ptr; // For global variables 32 | int64_t offset; // For functions (code offset) or local variables (stack offset) 33 | Const constant; // For constants 34 | int64_t moduleVal; // For modules 35 | }; 36 | DebugInfo debug; 37 | struct tagIdent *next; 38 | } Ident; 39 | 40 | 41 | typedef struct 42 | { 43 | Ident *first; 44 | Ident *lastTempVarForResult; 45 | int tempVarNameSuffix; 46 | Storage *storage; 47 | DebugInfo *debug; 48 | Error *error; 49 | } Idents; 50 | 51 | 52 | void identInit(Idents *idents, Storage *storage, DebugInfo *debug, Error *error); 53 | void identFree(Idents *idents, int block); 54 | 55 | const Ident *identFind (const Idents *idents, const Modules *modules, const Blocks *blocks, int module, const char *name, const Type *rcvType, bool markAsUsed); 56 | const Ident *identAssertFind (const Idents *idents, const Modules *modules, const Blocks *blocks, int module, const char *name, const Type *rcvType); 57 | const Ident *identFindModule (const Idents *idents, const Modules *modules, const Blocks *blocks, int module, const char *name, bool markAsUsed); 58 | const Ident *identAssertFindModule(const Idents *idents, const Modules *modules, const Blocks *blocks, int module, const char *name); 59 | 60 | bool identIsOuterLocalVar (const Blocks *blocks, const Ident *ident); 61 | 62 | Ident *identAddConst (Idents *idents, const Modules *modules, const Blocks *blocks, const char *name, const Type *type, bool exported, Const constant); 63 | Ident *identAddTempConst (Idents *idents, const Modules *modules, const Blocks *blocks, const Type *type, Const constant); 64 | Ident *identAddGlobalVar (Idents *idents, const Modules *modules, const Blocks *blocks, const char *name, const Type *type, bool exported, void *ptr); 65 | Ident *identAddLocalVar (Idents *idents, const Modules *modules, const Blocks *blocks, const char *name, const Type *type, bool exported, int offset); 66 | Ident *identAddType (Idents *idents, const Modules *modules, const Blocks *blocks, const char *name, const Type *type, bool exported); 67 | Ident *identAddBuiltinFunc(Idents *idents, const Modules *modules, const Blocks *blocks, const char *name, const Type *type, BuiltinFunc builtin); 68 | Ident *identAddModule (Idents *idents, const Modules *modules, const Blocks *blocks, const char *name, const Type *type, int moduleVal); 69 | 70 | int identAllocStack (Idents *idents, const Types *types, Blocks *blocks, const Type *type); 71 | Ident *identAllocVar (Idents *idents, const Types *types, const Modules *modules, Blocks *blocks, const char *name, const Type *type, bool exported); 72 | Ident *identAllocTempVar (Idents *idents, const Types *types, const Modules *modules, Blocks *blocks, const Type *type, bool isFuncResult); 73 | Ident *identAllocParam (Idents *idents, const Types *types, const Modules *modules, const Blocks *blocks, const Signature *sig, int index); 74 | 75 | const char *identMethodNameWithRcv(const Idents *idents, const Ident *method); 76 | 77 | void identWarnIfUnused (const Idents *idents, const Ident *ident); 78 | void identWarnIfUnusedAll (const Idents *idents, int block); 79 | bool identIsMain (const Ident *ident); 80 | 81 | static inline void identSetUsed(const Ident *ident) 82 | { 83 | ((Ident *)ident)->used = true; 84 | } 85 | 86 | #endif // UMKA_IDENT_H_INCLUDED 87 | -------------------------------------------------------------------------------- /src/umka_lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_LEXER_H_INCLUDED 2 | #define UMKA_LEXER_H_INCLUDED 3 | 4 | #include "umka_common.h" 5 | 6 | 7 | typedef enum 8 | { 9 | TOK_NONE, 10 | 11 | // Keywords 12 | TOK_BREAK, 13 | TOK_CASE, 14 | TOK_CONST, 15 | TOK_CONTINUE, 16 | TOK_DEFAULT, 17 | TOK_ELSE, 18 | TOK_ENUM, 19 | TOK_FN, 20 | TOK_FOR, 21 | TOK_IMPORT, 22 | TOK_INTERFACE, 23 | TOK_IF, 24 | TOK_IN, 25 | TOK_MAP, 26 | TOK_RETURN, 27 | TOK_STR, 28 | TOK_STRUCT, 29 | TOK_SWITCH, 30 | TOK_TYPE, 31 | TOK_VAR, 32 | TOK_WEAK, 33 | 34 | // Operators 35 | TOK_PLUS, 36 | TOK_MINUS, 37 | TOK_MUL, 38 | TOK_DIV, 39 | TOK_MOD, 40 | TOK_AND, 41 | TOK_OR, 42 | TOK_XOR, 43 | TOK_SHL, 44 | TOK_SHR, 45 | TOK_PLUSEQ, 46 | TOK_MINUSEQ, 47 | TOK_MULEQ, 48 | TOK_DIVEQ, 49 | TOK_MODEQ, 50 | TOK_ANDEQ, 51 | TOK_OREQ, 52 | TOK_XOREQ, 53 | TOK_SHLEQ, 54 | TOK_SHREQ, 55 | TOK_ANDAND, 56 | TOK_OROR, 57 | TOK_PLUSPLUS, 58 | TOK_MINUSMINUS, 59 | TOK_EQEQ, 60 | TOK_LESS, 61 | TOK_GREATER, 62 | TOK_EQ, 63 | TOK_QUESTION, 64 | TOK_NOT, 65 | TOK_NOTEQ, 66 | TOK_LESSEQ, 67 | TOK_GREATEREQ, 68 | TOK_COLONEQ, 69 | TOK_LPAR, 70 | TOK_RPAR, 71 | TOK_LBRACKET, 72 | TOK_RBRACKET, 73 | TOK_LBRACE, 74 | TOK_RBRACE, 75 | TOK_CARET, 76 | TOK_COMMA, 77 | TOK_SEMICOLON, 78 | TOK_COLON, 79 | TOK_COLONCOLON, 80 | TOK_PERIOD, 81 | TOK_ELLIPSIS, 82 | 83 | // Other tokens 84 | TOK_IDENT, 85 | TOK_INTNUMBER, 86 | TOK_REALNUMBER, 87 | TOK_CHARLITERAL, 88 | TOK_STRLITERAL, 89 | 90 | TOK_IMPLICIT_SEMICOLON, 91 | TOK_EOLN, 92 | TOK_EOF 93 | } TokenKind; 94 | 95 | 96 | typedef char IdentName[MAX_IDENT_LEN + 1]; 97 | 98 | 99 | typedef struct 100 | { 101 | TokenKind kind; 102 | union 103 | { 104 | struct 105 | { 106 | IdentName name; 107 | unsigned int hash; 108 | }; 109 | int64_t intVal; 110 | uint64_t uintVal; 111 | double realVal; 112 | char *strVal; 113 | }; 114 | int line, pos; 115 | } Token; 116 | 117 | 118 | typedef struct 119 | { 120 | char *fileName; 121 | bool hasSourceString, trusted; 122 | char *buf; 123 | int bufPos, line, pos; 124 | Token tok, prevTok; 125 | Storage *storage; 126 | DebugInfo *debug; 127 | Error *error; 128 | } Lexer; 129 | 130 | 131 | int lexInit(Lexer *lex, Storage *storage, DebugInfo *debug, const char *fileName, const char *sourceString, bool trusted, Error *error); 132 | void lexFree(Lexer *lex); 133 | void lexNext(Lexer *lex); 134 | void lexNextForcedSemicolon(Lexer *lex); 135 | bool lexCheck(Lexer *lex, TokenKind kind); 136 | void lexEat(Lexer *lex, TokenKind kind); 137 | const char *lexSpelling(TokenKind kind); 138 | TokenKind lexShortAssignment(TokenKind kind); 139 | 140 | 141 | #endif // UMKA_LEXER_H_INCLUDED 142 | -------------------------------------------------------------------------------- /src/umka_runtime.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_RUNTIME_H_INCLUDED 2 | #define UMKA_RUNTIME_H_INCLUDED 3 | 4 | #include "umka_api.h" 5 | 6 | 7 | typedef struct 8 | { 9 | int64_t second, minute, hour; 10 | int64_t day, month, year; 11 | int64_t dayOfWeek, dayOfYear; 12 | bool isDST; 13 | } RTLDateTime; 14 | 15 | 16 | typedef struct 17 | { 18 | char *fileName; 19 | char *fnName; 20 | int64_t line; 21 | } RTLErrPos; 22 | 23 | 24 | void rtlmemcpy (UmkaStackSlot *params, UmkaStackSlot *result); 25 | void rtlstdin (UmkaStackSlot *params, UmkaStackSlot *result); 26 | void rtlstdout (UmkaStackSlot *params, UmkaStackSlot *result); 27 | void rtlstderr (UmkaStackSlot *params, UmkaStackSlot *result); 28 | void rtlfopen (UmkaStackSlot *params, UmkaStackSlot *result); 29 | void rtlfopenSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 30 | void rtlfclose (UmkaStackSlot *params, UmkaStackSlot *result); 31 | void rtlfcloseSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 32 | void rtlfread (UmkaStackSlot *params, UmkaStackSlot *result); 33 | void rtlfreadSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 34 | void rtlfwrite (UmkaStackSlot *params, UmkaStackSlot *result); 35 | void rtlfwriteSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 36 | void rtlfseek (UmkaStackSlot *params, UmkaStackSlot *result); 37 | void rtlfseekSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 38 | void rtlftell (UmkaStackSlot *params, UmkaStackSlot *result); 39 | void rtlftellSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 40 | void rtlremove (UmkaStackSlot *params, UmkaStackSlot *result); 41 | void rtlremoveSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 42 | void rtlfeof (UmkaStackSlot *params, UmkaStackSlot *result); 43 | void rtlfeofSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 44 | void rtlfflush (UmkaStackSlot *params, UmkaStackSlot *result); 45 | void rtltime (UmkaStackSlot *params, UmkaStackSlot *result); 46 | void rtlclock (UmkaStackSlot *params, UmkaStackSlot *result); 47 | void rtllocaltime (UmkaStackSlot *params, UmkaStackSlot *result); 48 | void rtlgmtime (UmkaStackSlot *params, UmkaStackSlot *result); 49 | void rtlmktime (UmkaStackSlot *params, UmkaStackSlot *result); 50 | void rtlgetenv (UmkaStackSlot *params, UmkaStackSlot *result); 51 | void rtlgetenvSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 52 | void rtlsystem (UmkaStackSlot *params, UmkaStackSlot *result); 53 | void rtlsystemSandbox (UmkaStackSlot *params, UmkaStackSlot *result); 54 | void rtltrace (UmkaStackSlot *params, UmkaStackSlot *result); 55 | 56 | #endif // UMKA_RUNTIME_H_INCLUDED 57 | -------------------------------------------------------------------------------- /src/umka_stmt.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_STMT_H_INCLUDED 2 | #define UMKA_STMT_H_INCLUDED 3 | 4 | #include "umka_compiler.h" 5 | 6 | void doGarbageCollection(Compiler *comp); 7 | void doGarbageCollectionDownToBlock(Compiler *comp, int block); 8 | 9 | void doZeroVar(Compiler *comp, const Ident *ident); 10 | void doResolveExtern(Compiler *comp); 11 | 12 | void parseAssignmentStmt(Compiler *comp, const Type *type, Const *varPtrConstList); 13 | void parseDeclAssignmentStmt(Compiler *comp, IdentName *names, const bool *exported, int num, bool constExpr); 14 | 15 | void parseFnBlock(Compiler *comp, Ident *fn, const Type *upvaluesStructType); 16 | void parseFnPrototype(Compiler *comp, Ident *fn); 17 | 18 | 19 | #endif // UMKA_STMT_H_INCLUDED 20 | -------------------------------------------------------------------------------- /src/umka_vm.h: -------------------------------------------------------------------------------- 1 | #ifndef UMKA_VM_H_INCLUDED 2 | #define UMKA_VM_H_INCLUDED 3 | 4 | #include "umka_common.h" 5 | #include "umka_lexer.h" 6 | #include "umka_types.h" 7 | 8 | 9 | typedef enum 10 | { 11 | REG_RESULT, 12 | REG_SELF, 13 | REG_HEAP_COPY, 14 | REG_SWITCH_EXPR, 15 | REG_EXPR_LIST, 16 | 17 | NUM_REGS 18 | } RegisterIndex; 19 | 20 | 21 | enum // Memory manager settings 22 | { 23 | MEM_MIN_FREE_STACK = 1024, // Slots 24 | MEM_MIN_FREE_HEAP = 1024, // Bytes 25 | MEM_MIN_HEAP_CHUNK = 64, // Bytes 26 | MEM_MIN_HEAP_PAGE = 1024 * 1024, // Bytes 27 | }; 28 | 29 | 30 | enum // Special values for return addresses 31 | { 32 | RETURN_FROM_VM = -2, // Used instead of return address in functions called by umkaCall() 33 | RETURN_FROM_FIBER = -1 // Used instead of return address in fiber function calls 34 | }; 35 | 36 | 37 | enum // Runtime error codes 38 | { 39 | ERR_RUNTIME = -1 40 | }; 41 | 42 | 43 | typedef enum 44 | { 45 | OP_NOP, 46 | OP_PUSH, 47 | OP_PUSH_ZERO, 48 | OP_PUSH_LOCAL_PTR, 49 | OP_PUSH_LOCAL_PTR_ZERO, 50 | OP_PUSH_LOCAL, 51 | OP_PUSH_REG, 52 | OP_PUSH_UPVALUE, 53 | OP_POP, 54 | OP_POP_REG, 55 | OP_DUP, 56 | OP_SWAP, 57 | OP_ZERO, 58 | OP_DEREF, 59 | OP_ASSIGN, 60 | OP_ASSIGN_PARAM, 61 | OP_CHANGE_REF_CNT, 62 | OP_CHANGE_REF_CNT_GLOBAL, 63 | OP_CHANGE_REF_CNT_LOCAL, 64 | OP_CHANGE_REF_CNT_ASSIGN, 65 | OP_UNARY, 66 | OP_BINARY, 67 | OP_GET_ARRAY_PTR, 68 | OP_GET_DYNARRAY_PTR, 69 | OP_GET_MAP_PTR, 70 | OP_GET_FIELD_PTR, 71 | OP_ASSERT_TYPE, 72 | OP_ASSERT_RANGE, 73 | OP_WEAKEN_PTR, 74 | OP_STRENGTHEN_PTR, 75 | OP_GOTO, 76 | OP_GOTO_IF, 77 | OP_GOTO_IF_NOT, 78 | OP_CALL, 79 | OP_CALL_INDIRECT, 80 | OP_CALL_EXTERN, 81 | OP_CALL_BUILTIN, 82 | OP_RETURN, 83 | OP_ENTER_FRAME, 84 | OP_LEAVE_FRAME, 85 | OP_HALT 86 | } Opcode; 87 | 88 | 89 | typedef enum 90 | { 91 | // I/O 92 | BUILTIN_PRINTF, 93 | BUILTIN_FPRINTF, 94 | BUILTIN_SPRINTF, 95 | BUILTIN_SCANF, 96 | BUILTIN_FSCANF, 97 | BUILTIN_SSCANF, 98 | 99 | // Math 100 | BUILTIN_REAL, // Integer to real at stack top (right operand) 101 | BUILTIN_REAL_LHS, // Integer to real at stack top + 1 (left operand) - implicit calls only 102 | BUILTIN_ROUND, 103 | BUILTIN_TRUNC, 104 | BUILTIN_CEIL, 105 | BUILTIN_FLOOR, 106 | BUILTIN_ABS, 107 | BUILTIN_FABS, 108 | BUILTIN_SQRT, 109 | BUILTIN_SIN, 110 | BUILTIN_COS, 111 | BUILTIN_ATAN, 112 | BUILTIN_ATAN2, 113 | BUILTIN_EXP, 114 | BUILTIN_LOG, 115 | 116 | // Memory 117 | BUILTIN_NEW, 118 | BUILTIN_MAKE, 119 | BUILTIN_MAKEFROMARR, // Array to dynamic array - implicit calls only 120 | BUILTIN_MAKEFROMSTR, // String to dynamic array - implicit calls only 121 | BUILTIN_MAKETOARR, // Dynamic array to array - implicit calls only 122 | BUILTIN_MAKETOSTR, // Character or dynamic array to string - implicit calls only 123 | BUILTIN_COPY, 124 | BUILTIN_APPEND, 125 | BUILTIN_INSERT, 126 | BUILTIN_DELETE, 127 | BUILTIN_SLICE, 128 | BUILTIN_SORT, 129 | BUILTIN_SORTFAST, 130 | BUILTIN_LEN, 131 | BUILTIN_CAP, 132 | BUILTIN_SIZEOF, 133 | BUILTIN_SIZEOFSELF, 134 | BUILTIN_SELFPTR, 135 | BUILTIN_SELFHASPTR, 136 | BUILTIN_SELFTYPEEQ, 137 | BUILTIN_TYPEPTR, 138 | BUILTIN_VALID, 139 | 140 | // Maps 141 | BUILTIN_VALIDKEY, 142 | BUILTIN_KEYS, 143 | 144 | // Fibers 145 | BUILTIN_RESUME, 146 | 147 | // Misc 148 | BUILTIN_MEMUSAGE, 149 | BUILTIN_EXIT 150 | } BuiltinFunc; 151 | 152 | 153 | typedef union 154 | { 155 | int64_t intVal; // For all ordinal types except uint 156 | uint64_t uintVal; 157 | int32_t int32Val[2]; 158 | void *ptrVal; 159 | uint64_t weakPtrVal; // For global pointers, stores the pointer. For heap pointers, stores the heap flag (bit 63), page ID (bits 32...62), offset within page (bits 0..31) 160 | double realVal; // For all real types 161 | BuiltinFunc builtinVal; 162 | } Slot; 163 | 164 | 165 | typedef struct 166 | { 167 | Opcode opcode; 168 | Opcode inlineOpcode; // Inlined instruction (DEREF, SWAP): PUSH + DEREF, SWAP + ASSIGN etc. 169 | TokenKind tokKind; // Unary/binary operation token 170 | TypeKind typeKind; 171 | const Type *type; 172 | Slot operand; 173 | } Instruction; 174 | 175 | 176 | typedef struct 177 | { 178 | int64_t entryOffset; 179 | Slot *params; 180 | Slot *result; 181 | } FuncContext; 182 | 183 | 184 | typedef void (*ExternFunc)(Slot *params, Slot *result); 185 | 186 | 187 | typedef struct tagHeapPage 188 | { 189 | int id; 190 | int refCnt; 191 | int numChunks, numOccupiedChunks, numChunksWithOnFree, chunkSize; 192 | struct tagHeapPage *prev, *next; 193 | char *end; 194 | char data[]; 195 | } HeapPage; 196 | 197 | 198 | typedef struct 199 | { 200 | HeapPage *first; 201 | int freeId; 202 | int64_t totalSize; 203 | struct tagFiber *fiber; 204 | Error *error; 205 | } HeapPages; 206 | 207 | 208 | typedef struct 209 | { 210 | int refCnt; 211 | int size; 212 | const struct tagType *type; // Optional type for garbage collection 213 | ExternFunc onFree; // Optional callback called when ref count reaches zero 214 | int64_t ip; // Optional instruction pointer at which the chunk has been allocated 215 | bool isStack; 216 | bool reserved[7]; 217 | char data[]; 218 | } HeapChunk; 219 | 220 | 221 | typedef struct 222 | { 223 | void *ptr; 224 | const Type *type; 225 | HeapPage *pageForDeferred; // Mandatory for deferred ref count updates, NULL otherwise 226 | } RefCntChangeCandidate; 227 | 228 | 229 | typedef struct 230 | { 231 | RefCntChangeCandidate *stack; 232 | int top, capacity; 233 | Storage *storage; 234 | } RefCntChangeCandidates; 235 | 236 | 237 | typedef enum 238 | { 239 | HOOK_CALL, 240 | HOOK_RETURN, 241 | 242 | NUM_HOOKS 243 | } HookEvent; 244 | 245 | 246 | typedef void (*HookFunc)(const char *fileName, const char *funcName, int line); 247 | 248 | 249 | typedef struct tagFiber 250 | { 251 | // Must have 8 byte alignment 252 | const Instruction *code; 253 | int ip; 254 | Slot *stack, *top, *base; 255 | int stackSize; 256 | Slot reg[NUM_REGS]; 257 | struct tagFiber *parent; 258 | const DebugInfo *debugPerInstr; 259 | RefCntChangeCandidates *refCntChangeCandidates; 260 | struct tagVM *vm; 261 | bool alive; 262 | bool fileSystemEnabled; 263 | } Fiber; 264 | 265 | 266 | typedef struct tagVM 267 | { 268 | Fiber *fiber, *mainFiber; 269 | HeapPages pages; 270 | RefCntChangeCandidates refCntChangeCandidates; 271 | HookFunc hooks[NUM_HOOKS]; 272 | bool terminatedNormally; 273 | Storage *storage; 274 | Error *error; 275 | } VM; 276 | 277 | 278 | void vmInit (VM *vm, Storage *storage, int stackSize /* slots */, bool fileSystemEnabled, Error *error); 279 | void vmFree (VM *vm); 280 | void vmReset (VM *vm, const Instruction *code, const DebugInfo *debugPerInstr); 281 | void vmRun (VM *vm, FuncContext *fn); 282 | bool vmAlive (VM *vm); 283 | void vmKill (VM *vm); 284 | int vmAsm (int ip, const Instruction *code, const DebugInfo *debugPerInstr, char *buf, int size); 285 | bool vmUnwindCallStack (VM *vm, Slot **base, int *ip); 286 | void vmSetHook (VM *vm, HookEvent event, HookFunc hook); 287 | void *vmAllocData (VM *vm, int size, ExternFunc onFree); 288 | void vmIncRef (VM *vm, void *ptr); 289 | void vmDecRef (VM *vm, void *ptr); 290 | void *vmGetMapNodeData (VM *vm, Map *map, Slot key); 291 | char *vmMakeStr (VM *vm, const char *str); 292 | void vmMakeDynArray (VM *vm, DynArray *array, const Type *type, int len); 293 | int64_t vmGetMemUsage (VM *vm); 294 | const char *vmBuiltinSpelling (BuiltinFunc builtin); 295 | 296 | #endif // UMKA_VM_H_INCLUDED 297 | -------------------------------------------------------------------------------- /test_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd tests 4 | 5 | cd lib 6 | ./build_lib_linux.sh 7 | cd .. 8 | 9 | ../umka_linux/umka -warn all.um > actual.log 10 | ../umka_linux/umka -warn compare.um actual.log expected.log 11 | cd .. 12 | 13 | cd benchmarks 14 | ../umka_linux/umka -warn allbench.um > actual.log 15 | ../umka_linux/umka -warn ../tests/compare.um actual.log expected.log 16 | cd .. 17 | -------------------------------------------------------------------------------- /test_windows_mingw.bat: -------------------------------------------------------------------------------- 1 | cd tests 2 | 3 | cd lib 4 | cmd /r build_lib_windows_mingw.bat 5 | cd .. 6 | 7 | ..\umka_windows_mingw\umka -warn all.um > actual.log 8 | ..\umka_windows_mingw\umka -warn compare.um actual.log expected.log 9 | cd .. 10 | 11 | cd benchmarks 12 | ..\umka_windows_mingw\umka -warn allbench.um > actual.log 13 | ..\umka_windows_mingw\umka -warn ..\tests\compare.um actual.log expected.log 14 | cd .. 15 | -------------------------------------------------------------------------------- /tests/all.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "print.um" 3 | "binfileio.um" 4 | "dynarrays.um" 5 | "dynarrays2.um" 6 | "dynarrays3.um" 7 | "strings.um" 8 | "fibers.um" 9 | "fnctools.um" 10 | "gc.um" 11 | "gc2.um" 12 | "interfaces.um" 13 | "interfaces2.um" 14 | "interfaces3.um" 15 | "maps.um" 16 | "maps2.um" 17 | "multret.um" 18 | "multret2.um" 19 | "errors.um" 20 | "tour.um" 21 | "typeeq.um" 22 | "constfold.um" 23 | "itemptr.um" 24 | "safecast.um" 25 | "nonlocal.um" 26 | "weakptr.um" 27 | "weakptr2.um" 28 | "weakptr3.um" 29 | "byteconv.um" 30 | "utf8test.um" 31 | "utf8test2.um" 32 | "imports.um" 33 | "imports2.um" 34 | "imports3.um" 35 | "imports4.um" 36 | "closures.um" 37 | "closures2.um" 38 | "closures3.um" 39 | "nullstr.um" 40 | "vararg.um" 41 | "defparam.um" 42 | "datetime.um" 43 | "untypedlit.um" 44 | "ternary.um" 45 | "typeswitch.um" 46 | "redecl.um" 47 | "forinptr.um" 48 | "enums.um" 49 | "fwdtypes.um" 50 | "sorting.um" 51 | "optim.um" 52 | "extlib.um" 53 | ) 54 | 55 | fn main() { 56 | printf("\n\n>>> Printing\n\n"); print::test() 57 | printf("\n\n>>> Binary file I/O\n\n"); binfileio::test() 58 | printf("\n\n>>> Dynamic arrays - 1\n\n"); dynarrays::test() 59 | printf("\n\n>>> Dynamic arrays - 2\n\n"); dynarrays2::test() 60 | printf("\n\n>>> Dynamic arrays - 3\n\n"); dynarrays3::test() 61 | printf("\n\n>>> Strings\n\n"); strings::test() 62 | printf("\n\n>>> Fibers\n\n"); fibers::test() 63 | printf("\n\n>>> Functional tools\n\n"); fnctools::test() 64 | printf("\n\n>>> Garbage collection - 1\n\n"); gc::test() 65 | printf("\n\n>>> Garbage collection - 2\n\n"); gc2::test() 66 | printf("\n\n>>> Interfaces - 1\n\n"); interfaces::test() 67 | printf("\n\n>>> Interfaces - 2\n\n"); interfaces2::test() 68 | printf("\n\n>>> Interfaces - 3\n\n"); interfaces3::test() 69 | printf("\n\n>>> Maps - 1\n\n"); maps::test() 70 | printf("\n\n>>> Maps - 2\n\n"); maps2::test() 71 | printf("\n\n>>> Multiple returns\n\n"); multret::test() 72 | printf("\n\n>>> Multiple returns - 2\n\n"); multret2::test() 73 | printf("\n\n>>> Error handling\n\n"); errors::test() 74 | printf("\n\n>>> Language tour\n\n"); tour::test() 75 | printf("\n\n>>> Type equivalence\n\n"); typeeq::test() 76 | printf("\n\n>>> Constant folding\n\n"); constfold::test() 77 | printf("\n\n>>> Item pointers\n\n"); itemptr::test() 78 | printf("\n\n>>> Safe type casts\n\n"); safecast::test() 79 | printf("\n\n>>> Non-local scope\n\n"); nonlocal::test() 80 | printf("\n\n>>> Weak pointers - 1\n\n"); weakptr::test() 81 | printf("\n\n>>> Weak pointers - 2\n\n"); weakptr2::test() 82 | printf("\n\n>>> Weak pointers - 3\n\n"); weakptr3::test() 83 | printf("\n\n>>> Byte conversions\n\n"); byteconv::test() 84 | printf("\n\n>>> UTF-8 - 1\n\n"); utf8test::test() 85 | printf("\n\n>>> UTF-8 - 2\n\n"); utf8test2::test() 86 | printf("\n\n>>> Imports - 1\n\n"); imports::test() 87 | printf("\n\n>>> Imports - 2\n\n"); imports2::test() 88 | printf("\n\n>>> Imports - 3\n\n"); imports3::test() 89 | printf("\n\n>>> Imports - 4\n\n"); imports4::test() 90 | printf("\n\n>>> Closures - 1\n\n"); closures::test() 91 | printf("\n\n>>> Closures - 2\n\n"); closures2::test() 92 | printf("\n\n>>> Closures - 3\n\n"); closures3::test() 93 | printf("\n\n>>> Null strings\n\n"); nullstr::test() 94 | printf("\n\n>>> Variadic functions\n\n"); vararg::test() 95 | printf("\n\n>>> Default parameters\n\n"); defparam::test() 96 | printf("\n\n>>> Date/time\n\n"); datetime::test() 97 | printf("\n\n>>> Untyped literals\n\n"); untypedlit::test() 98 | printf("\n\n>>> Ternary operator\n\n"); ternary::test() 99 | printf("\n\n>>> Type switches\n\n"); typeswitch::test() 100 | printf("\n\n>>> Redeclarations\n\n"); redecl::test() 101 | printf("\n\n>>> Iteration by pointer\n\n"); forinptr::test() 102 | printf("\n\n>>> Enumerations\n\n"); enums::test() 103 | printf("\n\n>>> Forward declarations\n\n"); fwdtypes::test() 104 | printf("\n\n>>> Sorting\n\n"); sorting::test() 105 | printf("\n\n>>> Peephole optimizations\n\n"); optim::test() 106 | printf("\n\n>>> External libraries\n\n"); extlib::test() 107 | } 108 | -------------------------------------------------------------------------------- /tests/binfileio.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn write(name, s: str) { 4 | f, err := std::fopen(name, "wb") 5 | std::exitif(err) 6 | std::fwrite(f, &[]char(s)) 7 | std::fclose(f) 8 | } 9 | 10 | fn read(name: str): str { 11 | f, err := std::fopen(name, "rb") 12 | std::exitif(err) 13 | data, err := std::freadall(f) 14 | std::exitif(err) 15 | std::fclose(f) 16 | 17 | return str(data) 18 | } 19 | 20 | fn test*() { 21 | name := "fio.txt" 22 | write(name, "Hello World") 23 | printf(read(name) + '\n') 24 | std::remove(name) 25 | } 26 | 27 | fn main() { 28 | test() 29 | } -------------------------------------------------------------------------------- /tests/byteconv.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test*() { 4 | type Pt = struct {x, y: int16} 5 | p := Pt{23, -6} 6 | printf("%v\n", p) 7 | 8 | bytes := std::tobytes(&p) 9 | printf("%v\n", bytes) 10 | 11 | bytes[2]++ 12 | printf("%v\n", bytes) 13 | 14 | std::frombytes(&p, bytes) 15 | printf("%v\n", p) 16 | } 17 | 18 | fn main() { 19 | test() 20 | } -------------------------------------------------------------------------------- /tests/closures.um: -------------------------------------------------------------------------------- 1 | import "fnc.um" 2 | 3 | type Person = struct { 4 | name: str 5 | age: int 6 | sex: str 7 | } 8 | 9 | fn by_name_eq(n: str): fn (person: any): any { 10 | printf("running by_name_eq with name : %s\n", n) 11 | return fn (person: any): any |n| { 12 | printf("running by_name_eq with name : %v and person : %llv\n", n, Person(person)) 13 | return Person(person).name == n 14 | } 15 | } 16 | 17 | fn test*() { 18 | named_foo := by_name_eq("Foo") 19 | 20 | persons := []Person{ 21 | {"Foo", 24, "M"}, 22 | {"Bar", 23, "M"}, 23 | {"FooBar", 23, "F"}} 24 | 25 | mapped := fnc::Array(persons).transform(named_foo) 26 | printf("%v\n", mapped) 27 | } 28 | 29 | fn main() { 30 | test() 31 | } 32 | -------------------------------------------------------------------------------- /tests/closures2.um: -------------------------------------------------------------------------------- 1 | fn bar(f: fn (x: int): int) { 2 | y := f(2) 3 | printf("%v\n", y) 4 | } 5 | 6 | sqr := fn (x: int): int { 7 | return x * x 8 | } 9 | 10 | fn cube(x: int): int { 11 | return x * sqr(x) 12 | } 13 | 14 | fn foo(a: int): []fn (x: int): int { 15 | s := []str{"Hello", "World", '!'} 16 | 17 | f := fn (x: int): int |a| { 18 | return a * x 19 | } 20 | 21 | g := fn (x: int): int |s, a| { 22 | printf(" g: s = %v\n", s) 23 | return len(s) + a 24 | } 25 | 26 | h := fn (x: int): int { 27 | return 10 * x 28 | } 29 | 30 | const i = fn (x: int): int { 31 | return 15 * x 32 | } 33 | 34 | return {f, g, h, i, sqr, cube} 35 | } 36 | 37 | fn add(y: int): fn (x: int): int { 38 | return |y| { 39 | return x + y 40 | } 41 | } 42 | 43 | fn test*() { 44 | printf("%v\n", add(3)(5)) 45 | 46 | funcs := foo(42) 47 | for _, f in funcs { 48 | bar(f) 49 | } 50 | } 51 | 52 | fn main() { 53 | test() 54 | } -------------------------------------------------------------------------------- /tests/closures3.um: -------------------------------------------------------------------------------- 1 | /* 2 | This example computes Fibonacci numbers by counting the number of derivations of the "Fibonacci grammar": 3 | 4 | fib: "a"; 5 | "a", fib; 6 | "aa", fib. 7 | 8 | Original Algol-68 version by Eric Voss and Marcel van der Veer 9 | */ 10 | 11 | type Cont = fn (j: int) 12 | 13 | fn terminal(i: int, a, s: str, q: Cont) { 14 | if u := i + len(a); u <= len(s) { 15 | q(u) 16 | } 17 | } 18 | 19 | fn grammar_fib(i: int, s: str, q: Cont) { 20 | terminal(i, "a", s, q) 21 | terminal(i, "a", s, |s, q| {grammar_fib(j, s, q)}) 22 | terminal(i, "aa", s, |s, q| {grammar_fib(j, s, q)}) 23 | } 24 | 25 | fn test*() { 26 | for k := 1; k <= 10; k++ { 27 | sentence := "" 28 | for len(sentence) < k {sentence += "a"} 29 | 30 | nr_derivations := new(int) 31 | grammar_fib(0, sentence, |sentence, nr_derivations| { 32 | if j == len(sentence) { 33 | nr_derivations^++ 34 | } 35 | }) 36 | 37 | printf("Fibonacci number %v = %v\n", len(sentence), nr_derivations^) 38 | } 39 | } 40 | 41 | fn main() { 42 | test() 43 | } -------------------------------------------------------------------------------- /tests/compare.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn readall(name: str): []char { 4 | f, err := std::fopen(name, "rb") 5 | std::exitif(err) 6 | data, err := std::freadall(f) 7 | std::exitif(err) 8 | std::fclose(f) 9 | return data 10 | } 11 | 12 | fn main() { 13 | std::assert(std::argc() == 3, "Need two files to compare") 14 | 15 | buf1 := readall(std::argv(1)) 16 | buf2 := readall(std::argv(2)) 17 | 18 | var i, j: int 19 | var c1, c2: char 20 | 21 | for i < len(buf1) || j < len(buf2) { 22 | if i < len(buf1) { 23 | c1 = buf1[i] 24 | if c1 == '\r' || c1 == '\n' { 25 | i++ 26 | continue 27 | } 28 | } 29 | 30 | if j < len(buf2) { 31 | c2 = buf2[j] 32 | if c2 == '\r' || c2 == '\n' { 33 | j++ 34 | continue 35 | } 36 | } 37 | 38 | std::assert(c1 == c2, "Files differ") 39 | 40 | i++ 41 | j++ 42 | } 43 | 44 | std::assert(i == len(buf1) && j == len(buf2), "Files differ") 45 | 46 | printf("%d / %d bytes\n", i, j) 47 | printf("OK\n") 48 | } -------------------------------------------------------------------------------- /tests/constfold.um: -------------------------------------------------------------------------------- 1 | fn test*() { 2 | x := -1 + atan2(2, 7) + sqrt(2) * trunc(3.6) - 1 + log(exp(3)) - round(7) 3 | y := round(sin(3.14)) + 8 / 3 4 | 5 | b := 'b' >= 'a' 6 | c := fabs(sqrt(3) - 1.7) < 0.1 7 | 8 | printf("%v %v %v %v\n", x, y, b, c) 9 | } 10 | 11 | fn main() { 12 | test() 13 | } 14 | -------------------------------------------------------------------------------- /tests/datetime.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test*() { 4 | t := std::time() 5 | printf("%v\n", std::mktime(std::localtime(t)) - t) 6 | 7 | d := std::DateTime{year: 2022, month: 10, day: 2, hour: 15, minute: 13, second: 32} 8 | printf(std::timestr(d) + '\n') 9 | } 10 | 11 | fn main() { 12 | test() 13 | } -------------------------------------------------------------------------------- /tests/defparam.um: -------------------------------------------------------------------------------- 1 | type F = fn (s: str = "Hello"): str 2 | 3 | const foo = fn (s: str = "Hello"): str { 4 | return "foo: " + s 5 | } 6 | 7 | type P = struct { 8 | x, y: int 9 | } 10 | 11 | type I = interface { 12 | bar(a: int, b: real = 3.14, c: ^int = null, d: P = P{5, 7}, e: [2]int = [2]int{7, 8}, f: F = foo): P 13 | } 14 | 15 | type S = struct { 16 | state: int 17 | } 18 | 19 | fn (s: ^S) bar(a: int, b: real = 3.14, c: ^int = null, d: P = P{5, 7}, e: [2]int = [2]int{7, 8}, f: F = foo): P { 20 | printf("%v %v %v %v %v %v\n", a, b, c == null, d, e, f()) 21 | return d 22 | } 23 | 24 | fn check(f: F, i: I) { 25 | printf(f() + '\n') 26 | printf(f("World") + '\n') 27 | 28 | v := 5 29 | 30 | i.bar(2) 31 | i.bar(2, 6.28) 32 | i.bar(2, 6.28, &v) 33 | i.bar(2, 6.28, &v, P{42, 43}) 34 | i.bar(2, 6.28, &v, P{42, 43}, [2]int{9, 10}) 35 | i.bar(2, 6.28, &v, P{42, 43}, [2]int{9, 10}, f) 36 | } 37 | 38 | fn test*() { 39 | s := S{} 40 | check(foo, s) 41 | } 42 | 43 | fn main() { 44 | test() 45 | } -------------------------------------------------------------------------------- /tests/dynarrays.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn f(b: [11][2]^int) { 4 | for _, x in b { 5 | std::println("b: " + std::itoa(x[0]^) + " " + std::itoa(x[1]^)) 6 | } 7 | } 8 | 9 | fn slices() { 10 | a := []str{"Hello " + "World", "Hallo " + "Welt", "Salut " + "le Monde", "Privet " + "Mir"} 11 | 12 | printf("%v\n", slice(a, 0, 4)) 13 | printf("%v\n", slice(a, 0, 3)) 14 | printf("%v\n", slice(a, 0, 2)) 15 | printf("%v\n", slice(a, 0, 1)) 16 | printf("%v\n\n", slice(a, 0, 0)) 17 | 18 | printf("%v\n", slice(a, 1, 4)) 19 | printf("%v\n", slice(a, 2, 4)) 20 | printf("%v\n", slice(a, 3, 4)) 21 | printf("%v\n\n", slice(a, 4, 4)) 22 | 23 | printf("%v\n", slice(a, 1, 2)) 24 | printf("%v\n", slice(a, 1, 3)) 25 | printf("%v\n\n", slice(a, 1, 4)) 26 | 27 | printf("%v\n", slice(a, 2, 3)) 28 | printf("%v\n\n", slice(a, 2, 4)) 29 | 30 | printf("%v\n", slice(a, 1, -1)) 31 | printf("%v\n", slice(a, 1, -2)) 32 | printf("%v\n\n", slice(a, 1, -3)) 33 | 34 | printf("%v\n", slice(a, 0)) 35 | printf("%v\n", slice(a, 1)) 36 | printf("%v\n", slice(a, 2)) 37 | printf("%v\n", slice(a, 3)) 38 | printf("%v\n\n", slice(a, 4)) 39 | 40 | printf("%v\n", slice(a, 2, -2)) 41 | } 42 | 43 | fn insertions() { 44 | a := []str{"Hello" + ' ', "World"} 45 | b := insert(copy(a), 1, "My " + "Wonderful") 46 | c := insert(copy(b), 1, ", ") 47 | d := insert(copy(c), 0, "Oh" + ',' + " ") 48 | e := insert(copy(d), len(d), "!") 49 | 50 | printf("%v\n", a) 51 | printf("%v\n", b) 52 | printf("%v\n", c) 53 | printf("%v\n", d) 54 | printf("%v\n", e) 55 | 56 | printf("%v\n", insert(insert([]int{}, 0, 42), 1, 43)) 57 | } 58 | 59 | fn copies() { 60 | a := [][]int{[]int{5, 7}, []int{9, 11}} 61 | b := copy(a) 62 | a[1] = []int{10, 12} 63 | printf("%v %v\n", a, b) 64 | } 65 | 66 | fn test*() { 67 | a := make([][2]^int, 10) 68 | 69 | for i in a { 70 | a[i] = [2]^int {new(int), new(int)} 71 | a[i][0]^ = 5 * i 72 | a[i][1]^ = 7 * i 73 | } 74 | 75 | for _, x in a { 76 | std::println("a: " + std::itoa(x[0]^) + " " + std::itoa(x[1]^)) 77 | } 78 | 79 | std::println("Appending...") 80 | a = append(a, [2]^int {new(int), new(int)}) 81 | a[len(a) - 1][0]^ = 666 82 | a[len(a) - 1][1]^ = 777 83 | 84 | for _, x in a { 85 | std::println("a: " + std::itoa(x[0]^) + " " + std::itoa(x[1]^)) 86 | } 87 | 88 | f(a) 89 | 90 | std::println("Appending...") 91 | e := append(copy(a), [2]^int {new(int), new(int)}) 92 | e[len(e) - 1][0]^ = 876 93 | e[len(e) - 1][1]^ = 765 94 | 95 | for _, x in e { 96 | std::println("e: " + std::itoa(x[0]^) + " " + std::itoa(x[1]^)) 97 | } 98 | 99 | f := copy(e) 100 | 101 | del := 4 102 | std::println("Deleting #" + std::itoa(del) + "...") 103 | e = delete(e, del) 104 | 105 | for _, x in e { 106 | std::println("e: " + std::itoa(x[0]^) + " " + std::itoa(x[1]^)) 107 | } 108 | 109 | for _, x in f { 110 | std::println("f: " + std::itoa(x[0]^) + " " + std::itoa(x[1]^)) 111 | } 112 | 113 | c := []int{3, 4, 5} 114 | printf("c: %v\n", c) 115 | 116 | std::println("Appending...") 117 | c = append(c, []int{6, 7}) 118 | printf("c: %v\n", c) 119 | 120 | d := [][]int{[]int{666, 777}, [2]int{888, 999}} 121 | printf("d: %v\n", d) 122 | 123 | std::println("Appending...") 124 | d = append(d, [2]int {444, 555}) 125 | printf("d: %v\n", d) 126 | 127 | std::println("Inserting...") 128 | insertions() 129 | 130 | std::println("Slicing...") 131 | slices() 132 | 133 | std::println("Copying...") 134 | copies() 135 | } 136 | 137 | fn main() { 138 | test() 139 | } 140 | -------------------------------------------------------------------------------- /tests/dynarrays2.um: -------------------------------------------------------------------------------- 1 | fn foo(s: [3]str) { 2 | printf("foo: %v\n", s) 3 | 4 | s1 := str([]char([100]char([]char(s[1])))) 5 | s2 := str([]char(s[2])) 6 | 7 | printf("foo: " + s[1] + " = " + s1 + " : " + sprintf("%v", s[1] == s1) + '\n') 8 | printf("foo: " + s[2] + " = " + s2 + " : " + sprintf("%v", s[2] == s2) + '\n') 9 | } 10 | 11 | fn bar() { 12 | var b: [5][]int 13 | { 14 | a := [][]int{[]int{3, 5}, []int{4, 6, 8}, []int{9}} 15 | b = a 16 | } 17 | b[1][2] = -8 18 | 19 | b2 := [5][]int([][]int(b)) 20 | 21 | printf("bar: %v = %v\n", b, b2) 22 | } 23 | 24 | fn test1() { 25 | foo([]str{"Hello " + "World", "Hallo " + "Welt", "Salut " + "le Monde"}) 26 | bar() 27 | } 28 | 29 | fn test2() { 30 | a := []real([]int([]any([]int{5, 7, 9, 11, 13, 15, 17}))) 31 | printf("%v\n", a) 32 | 33 | b := []any([]int{42, 43, 44}) 34 | printf("%v %v\n", []^int(b)[1] != null, []^real(b)[1] != null) 35 | 36 | c := []str([][]char([]str{"Hello " + "World", "Privet " + "Mir", "Ha-" + "ha", "Ho-" + "ho"})) 37 | printf("%v\n", c) 38 | } 39 | 40 | 41 | fn test*() { 42 | test1() 43 | test2() 44 | } 45 | 46 | fn main() { 47 | test() 48 | } -------------------------------------------------------------------------------- /tests/dynarrays3.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn foo(name: str, words: []str = {"Hello", "World"}) { 4 | greeting := name + " says " 5 | for _, w in words { 6 | greeting += w + " " 7 | } 8 | printf("%s\n", greeting) 9 | } 10 | 11 | var x: []int = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17} 12 | y := []int{22, 23} 13 | 14 | var z: [][]real = { 15 | {1, 2, 3}, 16 | {4, 5, 6}, 17 | {7, 8.5} 18 | } 19 | 20 | var chars: []char = "Hahaha" 21 | 22 | fn test*() { 23 | printf("%v\n", x) 24 | 25 | ptr1 := &x[0] 26 | 27 | x = delete(x, 15) 28 | printf("%v\n", x) 29 | 30 | x = delete(x, 1) 31 | printf("%v\n", x) 32 | 33 | x = append(x, y) 34 | printf("%v\n", x) 35 | 36 | ptr2 := &x[0] 37 | std::assert(ptr1 == ptr2) 38 | 39 | for i := 0; i < 10; i++ { 40 | x = append(x, []int{66 + i, 77 + i}) 41 | } 42 | printf("%v\n", x) 43 | 44 | printf("%v\n", z) 45 | 46 | printf("%v\n", append(copy(chars), []char("-Hohoho"))) 47 | printf("%v\n", chars) 48 | 49 | foo("Vasiliy") 50 | foo("Umka", {"Meow", "Purr", "Meow"}) 51 | } 52 | 53 | fn main() { 54 | test() 55 | } -------------------------------------------------------------------------------- /tests/enums.um: -------------------------------------------------------------------------------- 1 | type Button = enum {left; middle; right} 2 | 3 | type Mode = enum (uint8) { 4 | draw = 74 5 | select 6 | remove = 8 7 | edit 8 | } 9 | 10 | fn print(m: Mode) { 11 | modeStr := map[Mode]str { 12 | .draw: "Draw", 13 | Mode.select: "Select", 14 | .remove: "Remove", 15 | Mode.edit: "Edit" 16 | } 17 | 18 | printf("%d: %s\n", m, modeStr[m]) 19 | } 20 | 21 | fn print2(m: Mode) { 22 | switch m { 23 | case .draw: printf("%d: Draw\n", m) 24 | case Mode.select: printf("%d: Select\n", m) 25 | case .remove: printf("%d: Remove\n", m) 26 | case .edit: printf("%d: Edit\n", m) 27 | case Mode(23): printf("%d: Code %d\n", m, m) 28 | default: printf("%d: \n", m) 29 | } 30 | } 31 | 32 | fn get(): (Mode, Button) { 33 | return .select, .left 34 | } 35 | 36 | fn test*() { 37 | print(.draw) 38 | print(Mode.select) 39 | print(Mode.remove) 40 | print(.edit) 41 | print(Mode(23)) 42 | 43 | printf("\n") 44 | 45 | print2(Mode.draw) 46 | print2(.select) 47 | print2(.remove) 48 | print2(Mode.edit) 49 | print2(Mode(23)) 50 | 51 | printf("\n") 52 | 53 | for _, m in []Mode{.draw, Mode.select, .remove, Mode.edit} { 54 | print(m) 55 | } 56 | 57 | printf("\n") 58 | 59 | for _, m in []Mode([]int{74, 75, 8, 9, 23, 42}) { 60 | print2(m) 61 | } 62 | 63 | printf("\n") 64 | 65 | lb := Button.left 66 | var mb, rb: Button 67 | mb, rb = .left, Button.right 68 | mb = .middle 69 | printf("%v %v %v\n", lb == mb, mb < rb, rb == Button(2)) 70 | 71 | printf("\n") 72 | 73 | m, b := get() 74 | printf("%v %v\n", m == Mode.select, b == .left) 75 | } 76 | 77 | fn main() { 78 | test() 79 | } -------------------------------------------------------------------------------- /tests/errors.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn foo(x: str): (int, std::Err) { 4 | if x == "" { 5 | return 0, std::error(-2, "Empty string", "foo") 6 | } 7 | return len(x), std::error() 8 | } 9 | 10 | fn fooTest(x: str) { 11 | res, err := foo(x) 12 | if err.code != 0 { 13 | printf("Error: %s (code %d) from %v:\n", err.msg, err.code, err.sender) 14 | for _, pos in err.trace { 15 | printf(" %s: (%d)\n", pos.func, pos.line) 16 | } 17 | return 18 | } 19 | printf("%v\n", res) 20 | } 21 | 22 | fn test*() { 23 | fooTest("blah") 24 | fooTest("") 25 | fooTest("blah blah") 26 | } 27 | 28 | fn main() { 29 | test() 30 | } -------------------------------------------------------------------------------- /tests/extlib.um: -------------------------------------------------------------------------------- 1 | import "lib/lib.um" 2 | 3 | fn test*() { 4 | a := 7 5 | printf("%f %v %s\n", 6 | lib::add(3, 5), 7 | lib::sum(|a| {return a * i * i}, 10) == a * (10 * 11 * 21) / 6, 8 | lib::hello() 9 | ) 10 | } 11 | 12 | fn main() { 13 | test() 14 | } -------------------------------------------------------------------------------- /tests/fibers.um: -------------------------------------------------------------------------------- 1 | fn test*() { 2 | a := new(int) 3 | b := new(int) 4 | 5 | child := make(fiber, |a, b| { 6 | 7 | c := new(int) 8 | d := new(int) 9 | 10 | grandchild := make(fiber, |a, c, d| { 11 | for i := 0; i < 13; i++ { 12 | printf(" Grandchild: i=%d a=%d c=%d\n", i, a^, c^) 13 | d^ = i * 11 14 | resume() 15 | } 16 | }) 17 | 18 | for i := 0; i < 5; i++ { 19 | for j := 0; j < 10; j++ { 20 | printf(" Child: i=%d a=%d d=%d\n", i, a^, d^) 21 | c^ = j * 19 22 | resume(grandchild) 23 | } 24 | 25 | b^ = i * 3 26 | resume() 27 | } 28 | }) 29 | 30 | for i := 0; i < 10; i++ { 31 | printf("Parent: i=%d b=%d\n", i, b^) 32 | a^ = i * 7 33 | resume(child) 34 | } 35 | } 36 | 37 | fn main() { 38 | test() 39 | } -------------------------------------------------------------------------------- /tests/fnctools.um: -------------------------------------------------------------------------------- 1 | import "fnc.um" 2 | 3 | fn test*() { 4 | data := []int{3, 7, 1, -4, 2, 5} 5 | printf("Array = %v\n", data) 6 | 7 | max := 30 8 | 9 | sqr := fn (x: any): any {return int(x) * int(x)} 10 | less := fn (x: any): bool |max| {return int(x) < max} 11 | sum := fn (x, y: any): any {return int(x) + int(y)} 12 | 13 | result := int(fnc::Array(data).transform(sqr).filter(less).reduce(sum)) 14 | printf("Sum of all squares less than %lld = %lld \n", max, result) 15 | } 16 | 17 | fn main() { 18 | test() 19 | } -------------------------------------------------------------------------------- /tests/forinptr.um: -------------------------------------------------------------------------------- 1 | fn print(arr: []^int) { 2 | for _, x in arr { 3 | printf("%v ", x^) 4 | } 5 | printf("\n") 6 | } 7 | 8 | fn updateVal(p: ^int) { 9 | p^++ 10 | } 11 | 12 | fn updatePtr(p: ^^int) { 13 | p^ = new(int, 3 * p^^) 14 | } 15 | 16 | fn test1() { 17 | var xs: [10]^int 18 | 19 | for i, px^ in xs { 20 | px^ = new(int, 2 * i) 21 | } 22 | 23 | print(xs) 24 | 25 | for _, px^ in xs { 26 | updatePtr(px) 27 | } 28 | 29 | print(xs) 30 | 31 | for _, px^ in xs { 32 | updateVal(px^) 33 | } 34 | 35 | print(xs) 36 | 37 | var as: [10]int 38 | for i, x in xs { 39 | as[i] = x^ 40 | } 41 | 42 | printf("%v\n", as) 43 | 44 | for _, a in as { 45 | a = 100 * a 46 | } 47 | 48 | printf("%v\n", as) 49 | 50 | for _, pa^ in as { 51 | pa^ = 100 * pa^ 52 | } 53 | 54 | printf("%v\n\n", as) 55 | } 56 | 57 | fn test2() { 58 | xs := make([]^int, 10) 59 | 60 | for i, px^ in xs { 61 | px^ = new(int, 2 * i) 62 | } 63 | 64 | print(xs) 65 | 66 | for _, px^ in xs { 67 | updatePtr(px) 68 | } 69 | 70 | print(xs) 71 | 72 | for _, px^ in xs { 73 | updateVal(px^) 74 | } 75 | 76 | print(xs) 77 | 78 | var as: []int 79 | for _, x in xs { 80 | as = append(as, x^) 81 | } 82 | 83 | printf("%v\n", as) 84 | 85 | for _, a in as { 86 | a = 100 * a 87 | } 88 | 89 | printf("%v\n", as) 90 | 91 | for _, pa^ in as { 92 | pa^ = 100 * pa^ 93 | } 94 | 95 | printf("%v\n\n", as) 96 | } 97 | 98 | fn test3() { 99 | type P = struct {x, y: real} 100 | 101 | var m: map[str]P = { 102 | "Russian": {0.1, 0.2}, 103 | "English": {0.3, 0.4}, 104 | "French": {0.5, 0.6} 105 | } 106 | 107 | printf("%v\n", m) 108 | 109 | for lang, val in m { 110 | val.y = val.x + 0.01 111 | } 112 | 113 | printf("%v\n", m) 114 | 115 | for lang, val^ in m { 116 | val.y = val.x + 0.01 117 | } 118 | 119 | printf("%v\n", m) 120 | } 121 | 122 | fn test*() { 123 | test1() 124 | test2() 125 | test3() 126 | } 127 | 128 | fn main() { 129 | test() 130 | } -------------------------------------------------------------------------------- /tests/fwdtypes.um: -------------------------------------------------------------------------------- 1 | import MapNode = "std.um" 2 | 3 | type ( 4 | MapNodeChildren = map[str]MapNode 5 | 6 | ArrNode = struct { 7 | name: str 8 | children: []ArrNode 9 | } 10 | 11 | MapNode = struct { 12 | name: str 13 | children: MapNodeChildren 14 | } 15 | ) 16 | 17 | fn test*() { 18 | arrtree := ArrNode{ 19 | "node1", 20 | { 21 | { 22 | "node11", 23 | {} 24 | }, 25 | { 26 | "node12", 27 | {} 28 | } 29 | } 30 | } 31 | 32 | arrtree.children[1].children = append(arrtree.children[1].children, {"node121", {}}) 33 | 34 | maptree := MapNode{ 35 | "node1", 36 | { 37 | "child1": { 38 | "node11", 39 | {} 40 | }, 41 | "child2": { 42 | "node12", 43 | {} 44 | } 45 | } 46 | } 47 | 48 | maptree.children["child2"].children["child21"] = {"node121", {}} 49 | 50 | printf("%llv\n\n%llv\n", arrtree, maptree) 51 | } 52 | 53 | fn main() { 54 | test() 55 | } -------------------------------------------------------------------------------- /tests/gc.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn g(q: ^int) {} 4 | 5 | fn f(p: ^int) { 6 | q := p 7 | g(q) 8 | } 9 | 10 | type st = struct { 11 | x: int 12 | p: ^int 13 | y: int 14 | q: ^int 15 | } 16 | 17 | fn h(s: st) { 18 | s.y = 5 19 | s.q = new(int) 20 | } 21 | 22 | fn f2() { 23 | d := new([1000] int) 24 | for i := 0; i < 10; i++ { 25 | a := new([1000] int) 26 | if i > 5 {return} 27 | } 28 | } 29 | 30 | fn g2(): ^int {a := new(int); return a} 31 | 32 | fn h2(): ^st { 33 | d := new(int) 34 | return &st{x: 7, p: d, y: 5, q: d} 35 | } 36 | 37 | fn foo(): int { 38 | var p: ^int 39 | { 40 | a := new([2]int) 41 | a[1] = 7 42 | p = &a[1] 43 | } 44 | return p^ 45 | } 46 | 47 | fn test*() { 48 | r := foo() 49 | 50 | a := new([1000] int) 51 | b := a 52 | c := &a[10] 53 | b = new([1000] int) 54 | f(&a[6]) 55 | e := new([3]real) 56 | e[2] = 7 57 | x := e[2] 58 | 59 | s := st {x: 2, p: new(int), y: 3, q: &a[11]} 60 | h(s) 61 | 62 | for i := 0; i < 1000; i++ { 63 | a := new([1000] int) 64 | a[2] = 7 65 | b := new(int) 66 | if i > 10 {break} 67 | } 68 | 69 | a = new([1000] int) 70 | i := 0 71 | for p := new([1000] int); i < 1000; i++ { 72 | r := new([1000] int) 73 | if i > 5 {continue} 74 | } 75 | 76 | f2() 77 | 78 | h2res := h2() 79 | h2res.p^ = 17 80 | 81 | g2res := g2() 82 | 83 | new([1000000] int) 84 | 85 | std::println("See any memory leak warnings?") 86 | } 87 | 88 | fn main() { 89 | test() 90 | } -------------------------------------------------------------------------------- /tests/gc2.um: -------------------------------------------------------------------------------- 1 | type list = struct { 2 | value: int 3 | next: ^list 4 | } 5 | 6 | fn test1() { 7 | var p: ^list 8 | 9 | for i := 0; i < 1000000; i++ { 10 | n := new(list) 11 | n.value = i 12 | n.next = p 13 | p = n 14 | } 15 | } 16 | 17 | fn test*() { 18 | test1() 19 | printf("Ok") 20 | } 21 | 22 | fn main() { 23 | test() 24 | } -------------------------------------------------------------------------------- /tests/imports.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "lib1/lib1.um" 3 | "lib2/lib2.um" 4 | ) 5 | 6 | fn test*() { 7 | lib1::f() 8 | lib2::f() 9 | } 10 | 11 | fn main() { 12 | test() 13 | } -------------------------------------------------------------------------------- /tests/imports2.um: -------------------------------------------------------------------------------- 1 | import ( 2 | utils1 = "lib1/utils.um" 3 | utils2 = "lib2/utils.um" 4 | ) 5 | 6 | fn test*() { 7 | utils1::f() 8 | utils2::f() 9 | } 10 | 11 | fn main() { 12 | test() 13 | } -------------------------------------------------------------------------------- /tests/imports3.um: -------------------------------------------------------------------------------- 1 | import s = "std.um" 2 | 3 | std := 42 4 | imports3 := 43 5 | 6 | fn test*() { 7 | s := "Hello" 8 | printf("%v %v %v %v\n", std, imports3, s::argc(), s) 9 | } 10 | 11 | fn main() { 12 | test() 13 | } -------------------------------------------------------------------------------- /tests/imports4.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "path with spaces/a.um" 3 | // " path with spaces/b.um " // This will fail 4 | // " " // This will fail 5 | // "path with spaces/module with spaces.um" // This will fail 6 | ) 7 | 8 | fn test*() { 9 | printf("A name: %s\n", a::Name) 10 | } 11 | 12 | fn main() { 13 | test() 14 | } -------------------------------------------------------------------------------- /tests/interfaces.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | type ( 4 | vec = struct { 5 | x, y: int 6 | p: [1000000] int 7 | } 8 | 9 | fooable = interface { 10 | foo(z: int) 11 | } 12 | 13 | fooable_barable = interface { 14 | bar(z: int) 15 | fooable 16 | } 17 | ) 18 | 19 | fn (v: ^vec) foo(z: int) { 20 | std::println(" foo: " + std::itoa(v.x) + ", " + std::itoa(v.y) + ", " + std::itoa(z)) 21 | } 22 | 23 | fn (v: ^vec) bar(z: int) { 24 | std::println(" bar: " + std::itoa(v.x) + ", " + std::itoa(v.y) + ", " + std::itoa(z)) 25 | } 26 | 27 | fn proc_fooable(f: fooable) { 28 | std::println("proc_fooable:") 29 | f.foo(7) 30 | } 31 | 32 | fn proc_fooable_barable(fb: fooable_barable) { 33 | std::println("proc_fooable_barable:") 34 | fb.foo(9) 35 | fb.bar(11) 36 | proc_fooable(fb) 37 | } 38 | 39 | fn test*() { 40 | var fb: fooable_barable 41 | 42 | if true { 43 | v := new(vec) 44 | v.x = 3 45 | v.y = 5 46 | fb = v 47 | } 48 | 49 | proc_fooable(fb) 50 | proc_fooable_barable(fb) 51 | 52 | f := fooable(fb) 53 | f = null 54 | } 55 | 56 | fn main() { 57 | test() 58 | } 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /tests/interfaces2.um: -------------------------------------------------------------------------------- 1 | fn customSort(a: []any, ordered: fn (x, y: any): bool): []any { 2 | for sorted := false; !sorted { 3 | sorted = true 4 | for i := 0; i < len(a) - 1; i++ { 5 | if !ordered(a[i], a[i + 1]) { 6 | a[i], a[i + 1] = a[i + 1], a[i] 7 | sorted = false 8 | } 9 | } 10 | } 11 | return a 12 | } 13 | 14 | fn test*() { 15 | a := []str{"red", "green", "blue", "yellow", "gray", "brown", "black", "cyan", "magenta", "white"} 16 | b := []str(customSort([]any(a), fn (x, y: any): bool {return str(x) < str(y)})) 17 | printf("%v\n%v\n", a, b) 18 | } 19 | 20 | fn main() { 21 | test() 22 | } -------------------------------------------------------------------------------- /tests/interfaces3.um: -------------------------------------------------------------------------------- 1 | type ( 2 | Dog = struct { woof_count: int } 3 | Cat = struct { meow_count: int } 4 | ) 5 | 6 | type Speaker = interface { 7 | speak(): str 8 | } 9 | 10 | fn (d: ^Dog) speak(): str { 11 | d.woof_count++ 12 | return "woof" 13 | } 14 | 15 | fn new_dog(): Speaker { 16 | return Dog { woof_count: 0 } 17 | } 18 | 19 | fn (c: ^Cat) speak(): str { 20 | c.meow_count++ 21 | return "meow" 22 | } 23 | 24 | fn new_cat(): Speaker { 25 | return Cat { meow_count: 0 } 26 | } 27 | 28 | fn test*() { 29 | for _, i in []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} { 30 | var a: Speaker 31 | if i % 3 == 1 { 32 | a = new_dog() 33 | } else { 34 | a = new_cat() 35 | } 36 | printf(a.speak() + '\n') 37 | } 38 | } 39 | 40 | fn main() { 41 | test() 42 | } -------------------------------------------------------------------------------- /tests/itemptr.um: -------------------------------------------------------------------------------- 1 | var p: ^^int 2 | 3 | fn test1() { 4 | a := new([2]^int) 5 | a^ = [2]^int{new(int), new(int)} 6 | a[1]^ = 15 7 | p = &a[1] 8 | printf("%v\n", p^^) 9 | } 10 | 11 | type ent = []int 12 | 13 | fn test2() { 14 | s := []^ent{} 15 | t := []ent{} 16 | 17 | for i := 0; i < 6; i++ { 18 | t = append(t, []int{i, 2 * i}) 19 | s = append(s, &t[len(t) - 1]) 20 | } 21 | 22 | printf("%v\n", t) 23 | 24 | for _, x in s { 25 | printf("%v\n", x^) 26 | } 27 | } 28 | 29 | fn test*() { 30 | test1() 31 | test2() 32 | } 33 | 34 | fn main() { 35 | test() 36 | } -------------------------------------------------------------------------------- /tests/lib/build_lib_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gcc -fPIC -O3 -c lib.c 4 | gcc -shared -fPIC -static-libgcc *.o -o lib.umi 5 | rm -f *.o 6 | -------------------------------------------------------------------------------- /tests/lib/build_lib_windows_mingw.bat: -------------------------------------------------------------------------------- 1 | gcc -O3 -c lib.c 2 | gcc -shared -Wl,--dll *.o -o lib.umi -static-libgcc -static 3 | del *.o 4 | -------------------------------------------------------------------------------- /tests/lib/lib.c: -------------------------------------------------------------------------------- 1 | #include "../../src/umka_api.h" 2 | 3 | 4 | UMKA_EXPORT void add(UmkaStackSlot *params, UmkaStackSlot *result) 5 | { 6 | void *umka = umkaGetInstance(result); 7 | UmkaAPI *api = umkaGetAPI(umka); 8 | 9 | double a = api->umkaGetParam(params, 0)->realVal; 10 | double b = api->umkaGetParam(params, 1)->realVal; 11 | api->umkaGetResult(params, result)->realVal = a + b; 12 | } 13 | 14 | 15 | UMKA_EXPORT void mulVec(UmkaStackSlot *params, UmkaStackSlot *result) 16 | { 17 | void *umka = umkaGetInstance(result); 18 | UmkaAPI *api = umkaGetAPI(umka); 19 | 20 | double a = api->umkaGetParam(params, 0)->realVal; 21 | double* v = (double *)api->umkaGetParam(params, 1); 22 | double* out = api->umkaGetResult(params, result)->ptrVal; 23 | 24 | out[0] = a * v[0]; 25 | out[1] = a * v[1]; 26 | } 27 | 28 | 29 | UMKA_EXPORT void hello(UmkaStackSlot *params, UmkaStackSlot *result) 30 | { 31 | void *umka = umkaGetInstance(result); 32 | UmkaAPI *api = umkaGetAPI(umka); 33 | 34 | api->umkaGetResult(params, result)->ptrVal = api->umkaMakeStr(umka, "Hello"); 35 | } 36 | 37 | UmkaFuncContext callbackContext = {0}; 38 | 39 | UMKA_EXPORT void sumImpl(UmkaStackSlot *params, UmkaStackSlot *result) 40 | { 41 | void *umka = umkaGetInstance(result); 42 | UmkaAPI *api = umkaGetAPI(umka); 43 | 44 | UmkaClosure *callback = (UmkaClosure *)api->umkaGetParam(params, 0); 45 | void *callbackType = api->umkaGetParam(params, 1)->ptrVal; 46 | int n = api->umkaGetParam(params, 2)->intVal; 47 | 48 | if (callbackContext.entryOffset != callback->entryOffset) 49 | { 50 | api->umkaMakeFuncContext(umka, callbackType, callback->entryOffset, &callbackContext); 51 | *api->umkaGetUpvalue(callbackContext.params) = callback->upvalue; 52 | } 53 | 54 | int sum = 0; 55 | for (int i = 1; i <= n; i++) 56 | { 57 | api->umkaGetParam(callbackContext.params, 0)->intVal = i; 58 | api->umkaIncRef(umka, callback->upvalue.data); 59 | 60 | api->umkaCall(umka, &callbackContext); 61 | sum += api->umkaGetResult(callbackContext.params, callbackContext.result)->intVal; 62 | } 63 | 64 | api->umkaGetResult(params, result)->intVal = sum; 65 | } -------------------------------------------------------------------------------- /tests/lib/lib.um: -------------------------------------------------------------------------------- 1 | fn add*(a, b: real): real 2 | fn mulVec*(a: real, v: [2]real): [2]real 3 | fn hello*(): str 4 | 5 | type Callback = fn (i: int): int 6 | fn sumImpl(callback: Callback, callbackType: ^void, n: int): int 7 | fn sum*(callback: Callback, n: int): int { 8 | return sumImpl(callback, typeptr(Callback), n) 9 | } -------------------------------------------------------------------------------- /tests/lib1/lib1.um: -------------------------------------------------------------------------------- 1 | import "utils.um" 2 | fn f*() {utils::f()} -------------------------------------------------------------------------------- /tests/lib1/utils.um: -------------------------------------------------------------------------------- 1 | fn f*() {printf("Utils from lib 1\n")} -------------------------------------------------------------------------------- /tests/lib2/lib2.um: -------------------------------------------------------------------------------- 1 | import "utils.um" 2 | fn f*() {utils::f()} -------------------------------------------------------------------------------- /tests/lib2/utils.um: -------------------------------------------------------------------------------- 1 | fn f*() {printf("Utils from lib 2\n")} -------------------------------------------------------------------------------- /tests/maps.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test1() { 4 | printf("\nTest 1\n") 5 | 6 | var populations: map[str]real 7 | f, err := std::fopen("countries.dat", "r") 8 | std::exitif(err) 9 | 10 | for true { 11 | var code, name, typ: str 12 | var year: int 13 | var pop: real 14 | 15 | num := fscanf(f, "%s %s %s %lld %lf\n", &code, &name, &typ, &year, &pop) 16 | if num != 5 {break} 17 | 18 | populations[name] = pop 19 | } 20 | 21 | std::fclose(f) 22 | 23 | russia2019 := populations["Russia"] 24 | 25 | populations["Russia"] = 146.748 26 | russia2020 := populations["Russia"] 27 | 28 | printf("Population of Russia was %.2f million. Now it is %.2f million\n\n", russia2019, russia2020) 29 | printf("%llv\n", populations) 30 | 31 | printf("\nCountries and regions more populous than Russia:\n") 32 | for country, pop in populations { 33 | if pop > russia2020 { 34 | printf("%40s: %.2f\n", country, pop) 35 | } 36 | } 37 | 38 | if !validkey(populations, "Russia") { 39 | exit(1,"Test failed") 40 | } 41 | 42 | populations = delete(populations, "Russia") 43 | 44 | if validkey(populations, "Russia") { 45 | exit(1, "Test failed") 46 | } 47 | } 48 | 49 | fn test2() { 50 | printf("\nTest 2\n") 51 | 52 | type Pair = [2]int 53 | var writers: map[Pair]str 54 | 55 | writers[Pair{1564, 1616}] = "Shakespeare" 56 | writers[Pair{1799, 1837}] = "Pushkin" 57 | writers[Pair{1828, 1910}] = "Tolstoy" 58 | writers[Pair{1749, 1832}] = "Goethe" 59 | 60 | pushkin := writers[Pair{1799, 1837}] 61 | printf(pushkin + "\n\n") 62 | 63 | if !validkey(writers, Pair{1799, 1837}) { 64 | exit(1, "Test failed") 65 | } 66 | 67 | for dates in writers { 68 | printf(writers[dates] + '\n') 69 | } 70 | 71 | writers = delete(writers, Pair{1799, 1837}) 72 | 73 | if validkey(writers, Pair{1799, 1837}) { 74 | exit(1, "Test failed") 75 | } 76 | 77 | printf("%v\n", writers) 78 | } 79 | 80 | fn test3() { 81 | printf("\nTest 3\n") 82 | 83 | a := 42 84 | b := 43 85 | 86 | pointers := make(map[^int]int) 87 | 88 | pointers[&a] = a 89 | pointers[&b] = b 90 | 91 | a1 := pointers[&a] 92 | b1 := pointers[&b] 93 | 94 | if a1 != a || b1 != b { 95 | exit(1, "Test failed") 96 | } 97 | 98 | printf("Test passed\n") 99 | } 100 | 101 | fn test*() { 102 | test1() 103 | test2() 104 | test3() 105 | } 106 | 107 | fn main() { 108 | test() 109 | } 110 | -------------------------------------------------------------------------------- /tests/maps2.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test1() { 4 | printf("\nTest 1\n") 5 | 6 | var m: map[str]str 7 | 8 | m["Hello" + " World"] = "English" + " EN" 9 | m["Salut" + " le Monde"] = "French" + " FR" 10 | 11 | printf("%v\n", validkey(m, "Salut le Monde")) 12 | 13 | m = delete(m, "Salut le Monde") 14 | 15 | printf("%v\n", validkey(m, "Salut le Monde")) 16 | 17 | a := m["Hello" + " World"] 18 | b := m["Privet" + " Mir"] 19 | c := m["Salut" + " le Monde"] 20 | 21 | printf("%v %v %v\n", a, b, c) 22 | printf("%v\n", keys(m)) 23 | printf("%v\n", valid(m)) 24 | printf("%v\n", m) 25 | } 26 | 27 | 28 | fn test2() { 29 | printf("\nTest 2\n") 30 | 31 | type Pt = struct { 32 | x, y: int 33 | } 34 | 35 | var p: ^str 36 | 37 | { 38 | m2 := make(map[Pt]str) 39 | 40 | m2[Pt{5, 7}] = "Good" 41 | m2[Pt{42, 23}] = "Better" 42 | 43 | printf("%v %v %v\n", m2[Pt{42, 23}], m2[Pt{11, 12}], m2[Pt{5, 7}]) 44 | 45 | k := keys(m2) 46 | printf("%d %v\n", len(m2), k) 47 | printf("%v\n", m2) 48 | 49 | p = &m2[Pt{42, 23}] 50 | } 51 | 52 | printf("%v\n", p^) 53 | } 54 | 55 | 56 | fn test3() { 57 | printf("\nTest 3\n") 58 | 59 | var m3: map[int]int 60 | printf("%v\n", valid(m3)) 61 | 62 | m3[1915] = 20 63 | printf("%v %v\n", valid(m3), m3[1915]) 64 | printf("%v\n", m3) 65 | } 66 | 67 | 68 | fn foo(): ^map[[2]int]str { 69 | return &map[[2]int]str{ 70 | [2]int{13, 15}: "So-so", 71 | [2]int{57, 89}: "Nice" 72 | } 73 | } 74 | 75 | 76 | fn test4() { 77 | printf("\nTest 4\n") 78 | 79 | m4 := foo() 80 | 81 | m4[[2]int{2, 5}] = "OK" 82 | m4[[2]int{7, 9}] = "Also OK" 83 | 84 | printf("%v\n", m4[[2]int{2, 5}]) 85 | printf("%v\n", m4^) 86 | 87 | for key, item in m4 { 88 | printf("%v %v\n", key, item) 89 | } 90 | } 91 | 92 | 93 | fn test5() { 94 | printf("\nTest 5\n") 95 | 96 | type Any = any 97 | m := make(map[int]Any) 98 | m[17] = 42 99 | m[19] = 53 100 | 101 | printf("%v\n", m) 102 | } 103 | 104 | 105 | fn test6() { 106 | printf("\nTest 6\n") 107 | 108 | m := map[str][]real{ 109 | "pi": []real{3.14, 6.28}, 110 | "e": []real{2.72, 5.44}, 111 | "ten": []real{10, 20} 112 | } 113 | 114 | n := copy(m) 115 | m["one"] = []real{1.0, 2.0} 116 | o := delete(copy(m), "pi") 117 | 118 | printf("%v\n", m) 119 | printf("%v\n", n) 120 | printf("%v\n", o) 121 | } 122 | 123 | 124 | fn test7(n: int) { 125 | printf("\nTest 7\n") 126 | 127 | var m: map[int]int 128 | 129 | cnt := 0 130 | 131 | for i := 0; i < n; i++ { 132 | k := std::rand() % n 133 | if !validkey(m, k) { 134 | cnt++ 135 | } 136 | m[k] = -k 137 | } 138 | 139 | std::assert(cnt == len(m)) 140 | 141 | for l := len(m); len(m) > l / 2 { 142 | ks := keys(m) 143 | ki := std::rand() % len(m) 144 | m = delete(m, ks[ki]) 145 | cnt-- 146 | } 147 | 148 | std::assert(cnt == len(m)) 149 | 150 | for k, v in m { 151 | std::assert(v == -k) 152 | cnt-- 153 | } 154 | 155 | std::assert(cnt == 0) 156 | } 157 | 158 | 159 | fn test*() { 160 | test1() 161 | test2() 162 | test3() 163 | test4() 164 | test5() 165 | test6() 166 | test7(10000) 167 | } 168 | 169 | 170 | fn main() { 171 | test() 172 | } 173 | -------------------------------------------------------------------------------- /tests/multret.um: -------------------------------------------------------------------------------- 1 | fn f(x: int, b: bool): (int32, [2]real32, bool) { 2 | return -x, [2]real32{2 * x, 3 * x}, !b 3 | } 4 | 5 | u, v, w := 23, 45.6, "Hello" 6 | p := 'z' 7 | 8 | var i, j, k: [2]char = [2]char{'a', 'b'}, [2]char{'c', 'd'}, [2]char{'e', 'f'} 9 | var l, m, n: real = 12, -3, 17 10 | 11 | fn foo(x: int): (real, str) { 12 | return x + 1, sprintf("[%v]", x + 1) 13 | } 14 | 15 | fn test*() { 16 | if a, b, c := f(3, false); a < 3 { 17 | printf("%v %v %v\n", a, b, c) 18 | 19 | a, b, c = f(4, true) 20 | printf("%v %v %v\n", a, b, c) 21 | } 22 | 23 | a, b, c := [2]int{3, 2}, [2]int{7, 6}, [2]int{9, 8} 24 | printf("%v %v %v\n", a, b, c) 25 | 26 | a, b, c = c, a, b 27 | printf("%v %v %v\n", a, b, c) 28 | 29 | var x, y, z: any = a, b, c 30 | printf("%v %v %v\n", a, b, c) 31 | 32 | s, t := "Hello", "World" 33 | printf(s + " " + t + "\n") 34 | 35 | s, t = t, s 36 | printf(s + " " + t + "\n") 37 | 38 | printf("%v %v %v %v\n", u, v, w, p) 39 | printf("%v %v %v\n", i, j, k) 40 | printf("%v %v %v\n", l, m, n) 41 | 42 | printf("%v %v\n", foo(7).item0 + 0.5, slice(foo(42).item1, 1, 3)) 43 | } 44 | 45 | fn main() { 46 | test() 47 | } -------------------------------------------------------------------------------- /tests/multret2.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn f(): (int, uint, char, int16) { 4 | return 5, 6, 'A', 7 5 | } 6 | 7 | fn g(): (int8, int8, str, real32) { 8 | return f() 9 | } 10 | 11 | fn test1() { 12 | printf("\nTest 1\n") 13 | a, b, c, d := g() 14 | printf("%v %v %v %v\n", a, b, c, d) 15 | } 16 | 17 | type Font = interface { 18 | validate() 19 | } 20 | 21 | type MyFont = struct { 22 | text: str 23 | } 24 | 25 | fn (f: ^MyFont) validate() { 26 | printf("Validation: %s\n", f.text) 27 | } 28 | 29 | fn loadMyFont(): (MyFont, std::Err) { 30 | fox, dog := "fox", "dog" 31 | return {"The quick brown " + fox + " jumps over the lazy " + dog}, std::error() 32 | } 33 | 34 | fn load(): (Font, std::Err) { 35 | return loadMyFont() 36 | } 37 | 38 | fn test2() { 39 | printf("\nTest 2\n") 40 | f, err := load() 41 | std::exitif(err) 42 | f.validate() 43 | } 44 | 45 | fn test*() { 46 | test1() 47 | test2() 48 | } 49 | 50 | fn main() { 51 | test() 52 | } 53 | -------------------------------------------------------------------------------- /tests/nonlocal.um: -------------------------------------------------------------------------------- 1 | a := 4 2 | 3 | fn f(): fn (z: int): int { 4 | type S = struct { 5 | x: int 6 | } 7 | 8 | const g = fn (y: int): int { 9 | return y * y 10 | } 11 | 12 | return fn (z: int): int { 13 | b := 6 14 | s := S{7} 15 | 16 | if z > 0 { 17 | return (z * g(z) - s.x) * a + b 18 | } 19 | return 0 20 | } 21 | } 22 | 23 | fn test*() { 24 | u := f() 25 | printf("%v\n", u(3)) 26 | } 27 | 28 | fn main() { 29 | test() 30 | } -------------------------------------------------------------------------------- /tests/nullstr.um: -------------------------------------------------------------------------------- 1 | fn testStr() { 2 | var s1, s2, s3: str 3 | s4 := "Hello " 4 | 5 | printf(s1) 6 | scanf(s1) 7 | 8 | printf("s2 = %s\n", s2) 9 | printf("%v %v %v %v\n", s1, s2, s3, s4) 10 | 11 | chars := []char(s2) 12 | printf("%v\n", chars) 13 | 14 | printf("len = %d, %d\n", len(s2), len(s4)) 15 | 16 | s5 := s1 + s2 + s4 + s3 17 | printf(s5 + '\n') 18 | 19 | printf("%v %v %v\n", s1 == s2, s1 < s2, s1 >= s2) 20 | printf("%v %v %v\n", s1 == s4, s1 < s4, s1 >= s4) 21 | } 22 | 23 | fn checkArr(a: []str) { 24 | printf('\n' + "%v" + '\n', a) 25 | for i, x in a { 26 | printf(" Item #%v = %v\n", i, x) 27 | } 28 | printf("len = %d cap = %d\n", len(a), cap(a)) 29 | } 30 | 31 | fn testArr() { 32 | var a, b, c: []str 33 | c = []str{"Hel" + "lo", "Wor" + "ld"} 34 | 35 | checkArr(a) 36 | checkArr(b) 37 | checkArr(c) 38 | checkArr(append(copy(a), b)) 39 | checkArr(append(copy(a), c)) 40 | checkArr(append(copy(c), a)) 41 | checkArr(insert(copy(a), 0, c[1])) 42 | checkArr(slice(a, 0, 0)) 43 | 44 | printf("\n%v %v\n", [2]str(a), [2]str(c)) 45 | 46 | var d: []char 47 | printf("%v\n", str(d)) 48 | } 49 | 50 | fn checkMap(a: map[str]str) { 51 | printf('\n' + "%v" + '\n', a) 52 | for i, x in a { 53 | printf(" Item %v = %v\n", i, x) 54 | } 55 | printf("len = %d\n", len(a)) 56 | } 57 | 58 | fn mk(): map[str]str { 59 | var e: map[str]str 60 | return e 61 | } 62 | 63 | fn testMap() { 64 | var a, b, c, d: map[str]str 65 | c = map[str]str{"Hel" + "lo": "Wor" + "ld"} 66 | 67 | b = mk() 68 | 69 | b["Ha" + "ha"] = "Ho" + "ho" 70 | b["He" + "he"] = "Hu" + "hu" 71 | 72 | d["Bu" + "bu"] = "Bo" + "bo" 73 | 74 | checkMap(a) 75 | checkMap(b) 76 | checkMap(c) 77 | checkMap(d) 78 | 79 | printf("%v %v\n", validkey(a, "Haha"), validkey(b, "Haha")) 80 | } 81 | 82 | fn test*() { 83 | testStr() 84 | testArr() 85 | testMap() 86 | } 87 | 88 | fn main() { 89 | test() 90 | } -------------------------------------------------------------------------------- /tests/optim.um: -------------------------------------------------------------------------------- 1 | fn g(): bool { 2 | return false 3 | } 4 | 5 | fn f(): bool { 6 | b := true 7 | g() 8 | return b || g() 9 | } 10 | 11 | fn test1() { 12 | printf("%v\n", f()) 13 | } 14 | 15 | fn test2() { 16 | x := 3.141 17 | x = true ? 1 : -1 18 | printf("%g\n", x) 19 | } 20 | 21 | fn test*() { 22 | test1() 23 | test2() 24 | } 25 | 26 | fn main() { 27 | test() 28 | } -------------------------------------------------------------------------------- /tests/path with spaces/a.um: -------------------------------------------------------------------------------- 1 | 2 | const Name* = "a.um" -------------------------------------------------------------------------------- /tests/path with spaces/b.um: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/tests/path with spaces/b.um -------------------------------------------------------------------------------- /tests/path with spaces/module with spaces.um: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vtereshkov/umka-lang/abadde6c19282283df03d0cb17db38f1c8b93c4c/tests/path with spaces/module with spaces.um -------------------------------------------------------------------------------- /tests/print.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test*() { 4 | printf("%d %v %f %v\n", 7, []int{42, 43}, 6.0, map[str]real{"Hello": 3.14, "World": 1 / 3.0}) 5 | 6 | s := sprintf("%d %v %f %v\n", 7, []int{42, 43}, 6.0, map[str]real{"Hello": 3.14, "World": 1 / 3.0}) 7 | printf("%s", s) 8 | 9 | f, err := std::fopen("test.txt", "w") 10 | std::exitif(err) 11 | fprintf(f, "%d %v %f %v\n", 7, []int{42, 43}, 6.0, map[str]real{"Hello": 3.14, "World": 1 / 3.0}) 12 | std::fclose(f) 13 | 14 | f2, err := std::fopen("test.txt", "rb") 15 | std::exitif(err) 16 | chars, err := std::freadall(f2) 17 | std::exitif(err) 18 | std::fclose(f2) 19 | printf("%s", str(chars)) 20 | } 21 | 22 | fn main() { 23 | test() 24 | } -------------------------------------------------------------------------------- /tests/redecl.um: -------------------------------------------------------------------------------- 1 | excl := "!" 2 | 3 | fn f(): (int, str, bool) { 4 | return 42, "OK" + excl, true 5 | } 6 | 7 | fn g(): (int, str, bool) { 8 | return 43, "FAIL" + excl, false 9 | } 10 | 11 | fn test1*() { 12 | res, err, ok := f() 13 | printf("f(): %v %v %v\n", res, err, ok) 14 | 15 | res, err, ok = g() 16 | printf("g(): %v %v %v\n", res, err, ok) 17 | 18 | res2, err, ok := f() 19 | printf("f(): %v %v %v\n", res2, err, ok) 20 | } 21 | 22 | a, b, c := "Hello " + "World!", true, [2]int{11, 13} 23 | a, d, c := "Merry " + "Christmas!", 0.333, [2]int{5, 7} 24 | 25 | fn test2*() { 26 | printf("%v %v %v %v\n", a, b, c, d) 27 | 28 | b, d, e := false, 144, "Hmmm" 29 | printf("%v %v %v %v %v\n", a, b, c, d, e) 30 | } 31 | 32 | fn test*() { 33 | test1() 34 | test2() 35 | } 36 | 37 | fn main() { 38 | test() 39 | } -------------------------------------------------------------------------------- /tests/safecast.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test1() { 4 | // Pointers 5 | p := new(int, 42) 6 | var q: ^void 7 | 8 | q = p 9 | printf("%v %v %v %v %v %v\n", p != q, q == p, p == null, null != p, q == null, null != q) 10 | 11 | printf("%v\n", p^) 12 | 13 | p = null 14 | printf("%v %v %v %v %v %v\n", p != q, q == p, p == null, null != p, q == null, null != q) 15 | 16 | a := 42 + 13 * 256 17 | b := ^[8]uint8(&a)^ 18 | printf("%v\n", b) 19 | } 20 | 21 | fn test2() { 22 | // Dynamic arrays 23 | var p: [3]int 24 | { 25 | a := []int{1, 4, 7} 26 | 27 | p = [3]int(a) 28 | a = append(a, 10) 29 | a[1] = 5 30 | 31 | printf("%v\n", a) 32 | } 33 | 34 | printf("%v\n", p) 35 | 36 | // Strings 37 | pc := []char{} 38 | 39 | { 40 | s := "Hello" 41 | pc = s 42 | s = "Hey " + s 43 | 44 | printf(s + '\n') 45 | } 46 | 47 | pc[len(pc) - 1] = '\0' 48 | 49 | var s2: str = pc 50 | 51 | printf(sprintf("%v ", pc) + s2 + '\n') 52 | printf(str(pc) + s2 + '\n') 53 | printf(s2 + str(pc) + '\n') 54 | } 55 | 56 | fn test3() { 57 | a := [2]int{5, 7} 58 | b := []int{5, 7} 59 | 60 | std::assert(a == b) 61 | std::assert(b == a) 62 | 63 | c := "ab" 64 | d := []char{'a', 'b'} 65 | 66 | std::assert(c == d) 67 | std::assert(d == c) 68 | 69 | std::assert(c + d == "abab") 70 | std::assert(d + c == "abab") 71 | } 72 | 73 | fn test4() { 74 | s := "Hello," 75 | a := []uint8(s + " Brave New World!") 76 | b := []uint8(s + " дивный новый мир!") 77 | printf("%v\n%v\n", a, b) 78 | printf("%s\n%s\n", str(a), str(b)) 79 | } 80 | 81 | fn test5() { 82 | b := []char{'P', 'Q'} 83 | b = append(b, 'R') 84 | b = delete(b, 2) 85 | printf("%v %v %v %v\n", b, str(b), len(b), len(str(b))) 86 | 87 | c := []char{'P', 'Q', '\0', 'S'} 88 | c = append(c, 'R') 89 | c = delete(c, 3) 90 | printf("%v %v %v %v\n", c, str(c), len(c), len(str(c))) 91 | } 92 | 93 | fn test*() { 94 | test1() 95 | test2() 96 | test3() 97 | test4() 98 | test5() 99 | } 100 | 101 | fn main() { 102 | test() 103 | } 104 | -------------------------------------------------------------------------------- /tests/sorting.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test1() { 4 | x := []real{2.3, 7.6, -11.8, 0.4, 15.0, -7.1} 5 | 6 | for _, ascending in []bool{false, true} { 7 | sort(x, |ascending| { 8 | d := a^ - b^ 9 | r := ascending ? 1 : -1 10 | return d == 0.0 ? 0 : d > 0.0 ? r : -r 11 | }) 12 | 13 | printf("%v\n\n", x) 14 | } 15 | } 16 | 17 | fn test2() { 18 | x := []map[str]str{ 19 | { 20 | "name": "Leo", 21 | "surname": "Tolstoy", 22 | "date": sprintf("%d", 1828) 23 | }, 24 | { 25 | "name": "Alexander", 26 | "surname": "Pushkin", 27 | "date": sprintf("%d", 1799) 28 | }, 29 | { 30 | "name": "Alexander", 31 | "surname": "Pope", 32 | "date": sprintf("%d", 1688) 33 | }, 34 | { 35 | "name": "Anton", 36 | "surname": "Chekhov", 37 | "date": sprintf("%d", 1860) 38 | } 39 | } 40 | 41 | for _, field in []str{"name", "surname", "date"} { 42 | sort(x, |field| { 43 | if s1, s2 := a[field], b[field]; s1 > s2 { 44 | return 1 45 | } else if s1 < s2 { 46 | return -1 47 | } 48 | return 0 49 | }) 50 | 51 | printf("Sorting by %s:\n%llv\n\n", field, x) 52 | } 53 | } 54 | 55 | fn test3() { 56 | x := []int{} 57 | for i := 0; i < 100000; i++ { 58 | x = append(x, std::rand()) 59 | } 60 | 61 | sort(x, {return a^ > b^ ? 1 : a^ == b^ ? 0 : -1}) 62 | 63 | for i := 0; i < len(x) - 1; i++ { 64 | std::assert(x[i + 1] >= x[i]) 65 | } 66 | } 67 | 68 | fn test4() { 69 | sort([]int{}, {std::assert(false); return 0}) 70 | } 71 | 72 | fn test5() { 73 | x := []real{2.3, 7.6, -11.8, 0.4, 15.0, -7.1} 74 | 75 | for _, ascending in []bool{false, true} { 76 | sort(x, ascending) 77 | printf("%v\n\n", x) 78 | } 79 | } 80 | 81 | fn test6() { 82 | x := []str{"red", "green", "blue", "yellow", "gray", "brown", "black", "cyan", "magenta", "white"} 83 | 84 | for _, ascending in []bool{false, true} { 85 | sort(x, ascending) 86 | printf("%v\n\n", x) 87 | } 88 | 89 | y := make([]str, 10) 90 | y[5] = "hi" 91 | y[8] = "bye" 92 | 93 | sort(y, false) 94 | printf("%v\n\n", y) 95 | } 96 | 97 | fn test7() { 98 | x := []int{} 99 | for i := 0; i < 100000; i++ { 100 | x = append(x, std::rand()) 101 | } 102 | 103 | sort(x, true) 104 | 105 | for i := 0; i < len(x) - 1; i++ { 106 | std::assert(x[i + 1] >= x[i]) 107 | } 108 | } 109 | 110 | fn test8() { 111 | type Vec = struct { 112 | x, y, z: real32 113 | } 114 | 115 | v := []Vec{} 116 | for i := 0; i < 10000; i++ { 117 | v = append(v, {std::rand(), std::rand(), std::rand()}) 118 | } 119 | 120 | sort(v, true, z) 121 | 122 | for i := 0; i < len(v) - 1; i++ { 123 | std::assert(v[i + 1].z >= v[i].z) 124 | } 125 | } 126 | 127 | fn test9() { 128 | sort([]int{}, true) 129 | } 130 | 131 | fn test*() { 132 | test1() 133 | test2() 134 | test3() 135 | test4() 136 | test5() 137 | test6() 138 | test7() 139 | test8() 140 | test9() 141 | } 142 | 143 | fn main() { 144 | test() 145 | } -------------------------------------------------------------------------------- /tests/strings.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn test*() { 4 | printf("Left trimming\n") 5 | 6 | printf("%v\n", std::ltrim("Hello World")) 7 | printf("%v\n", std::ltrim(" Hello World")) 8 | printf("%v\n", std::ltrim("Hello World ")) 9 | printf("%v\n", std::ltrim(" \tHello World ")) 10 | printf("%v\n", std::ltrim(" ")) 11 | printf("%v\n", std::ltrim("")) 12 | 13 | printf("Right trimming\n") 14 | 15 | printf("%v\n", std::rtrim("Hello World")) 16 | printf("%v\n", std::rtrim(" Hello World")) 17 | printf("%v\n", std::rtrim("Hello World ")) 18 | printf("%v\n", std::rtrim(" \tHello World ")) 19 | printf("%v\n", std::rtrim(" ")) 20 | printf("%v\n", std::rtrim("")) 21 | 22 | printf("Left & right trimming\n") 23 | 24 | printf("%v\n", std::trim("Hello World")) 25 | printf("%v\n", std::trim(" Hello World")) 26 | printf("%v\n", std::trim("Hello World ")) 27 | printf("%v\n", std::trim(" \tHello World ")) 28 | printf("%v\n", std::trim(" ")) 29 | printf("%v\n", std::trim("")) 30 | } 31 | 32 | fn main() { 33 | test() 34 | } 35 | -------------------------------------------------------------------------------- /tests/ternary.um: -------------------------------------------------------------------------------- 1 | fn f(x: int): real { 2 | return x < 3 ? 42.0 : 17 3 | } 4 | 5 | g1 := 2 < 3 ? 42.0 : 17 6 | g2 := 4 < 3 ? 42.0 : 17 7 | 8 | const ( 9 | gexc = '!' 10 | garg = 'T' 11 | gvehicle = (garg == 'B') ? "bus" + gexc : 12 | (garg == 'A') ? "airplane" + gexc : 13 | (garg == 'T') ? "train" + gexc : 14 | (garg == 'C') ? "car" + gexc : 15 | (garg == 'H') ? "horse" + gexc : 16 | "feet" + gexc 17 | ) 18 | 19 | fn test*() { 20 | printf("%v %v\n", f(2), f(4)) 21 | printf("%v %v\n", g1, g2) 22 | 23 | for i := 0; i < 10; i++ { 24 | s := "Hello" + "World" 25 | s = i % 2 == 0 ? sprintf("%d %d ", 5, 6) + sprintf("%f %f ", 7.0, 8.0) + sprintf("%v %v ", 9, 10) : sprintf("%d %d ", 15, 16) + "and nothing more" 26 | printf("%d: %s\n", i, s) 27 | } 28 | 29 | for i := 0; i < 10; i++ { 30 | p := i > 3 && i < 7 ? []real{3, 5.5, 7} : []real([]int{-4, 12}) 31 | printf("%d: %v\n", i, p) 32 | } 33 | 34 | 35 | exc := '!' 36 | arg := 'T' 37 | vehicle := (arg == 'B') ? "bus" + exc : 38 | (arg == 'A') ? "airplane" + exc : 39 | (arg == 'T') ? "train" + exc : 40 | (arg == 'C') ? "car" + exc : 41 | (arg == 'H') ? "horse" + exc : 42 | "feet" + exc 43 | 44 | printf("%s %s\n", vehicle, gvehicle) 45 | } 46 | 47 | fn main() { 48 | test() 49 | } -------------------------------------------------------------------------------- /tests/tour.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | // Constants 4 | const a = 3 5 | const b* = 2.38 // Exported identifier 6 | const ( 7 | c = sin(b) / 5 8 | d = "Hello" + " World" 9 | ) 10 | 11 | // Types 12 | type IntPtr = ^uint16 13 | type Arr = [a]real 14 | type ( 15 | MyMap = map[str]real 16 | Quat = struct { 17 | q: [4]real 18 | normalized: bool 19 | } 20 | Printable = interface { 21 | print(): int 22 | } 23 | ErrFn = fn(code: int) 24 | ) 25 | 26 | // Variables 27 | var e: int 28 | var f: str = d + '!' 29 | var ( 30 | g: Arr = [3]real{2.3, -4.1 / 2, b} 31 | h: [][5]int // Dynamic arrays require calling make() 32 | m: MyMap 33 | ) 34 | q := Quat{q: [4]real{1, 0, 0, 0}, normalized: true} 35 | 36 | // Functions 37 | fn tan(x: real): real {return sin(x) / cos(x)} 38 | fn getValue(): (int, bool) {return 42, true} 39 | 40 | // Methods 41 | fn (a: ^Arr) print(): int { 42 | printf("Arr: %v\n", a^) 43 | return 0 44 | } 45 | 46 | // Fibers 47 | fn fibers() { 48 | a := new(int) 49 | child := make(fiber, |a| { 50 | for i := 0; i < 5; i++ { 51 | std::println("Child : i=" + std::itoa(i) + " buf=" + std::itoa(a^)) 52 | a^ = i * 3 53 | resume() 54 | } 55 | }) 56 | for i := 0; i < 10; i++ { 57 | std::println("Parent: i=" + std::itoa(i) + " buf=" + std::itoa(a^)) 58 | a^ = i * 7 59 | resume(child) 60 | } 61 | } 62 | 63 | fn test*() { 64 | // Assignment 65 | h = make([][5]int, 3) 66 | m = make(MyMap) 67 | m["Hello Umka"] = 3.14 68 | 69 | // Declaration via assignment (with type inference) 70 | sum := 0.0 71 | 72 | // Function call 73 | y := tan(30 * std::pi / 180) 74 | h = append(h, [5]int{10, 20, 30, 40, 50}) 75 | 76 | // Method call 77 | g.print() 78 | 79 | // Conditional 80 | if x, ok := getValue(); ok { 81 | printf("Got %v\n", x) 82 | } 83 | 84 | // Switch 85 | switch a { 86 | case 1, 3, 5, 7: std::println(std::itoa(a) + " is odd") 87 | case 2, 4, 6, 8: std::println(std::itoa(a) + " is even") 88 | default: std::println("I don't know") 89 | } 90 | 91 | // Loop 92 | for k := 1; k <= 128; k *= 2 { 93 | printf("%v\n", k) 94 | } 95 | 96 | for i, x in g { 97 | if fabs(x) > 1e12 {break} 98 | if x < 0 {continue} 99 | sum += x 100 | } 101 | 102 | 103 | std::println("len = " + std::itoa(len(h))) 104 | std::println(std::ftoa(sum, 3)) 105 | 106 | 107 | // Interfaces 108 | var printable: Printable = Arr{0.5, 0.7, 0.9} 109 | printable.print() 110 | 111 | // Fibers 112 | fibers() 113 | 114 | // String representation 115 | printf("\nString representation:\n") 116 | printf("%v\n", a) 117 | printf("%v\n", b) 118 | printf("%v\n", c) 119 | printf("%v\n", d) 120 | printf("%v\n", e) 121 | printf("%v\n", f) 122 | printf("%v\n", g) 123 | printf("%v\n", h) 124 | printf("%v\n", m) 125 | printf("%v\n", q) 126 | printf("%v\n", sum) 127 | printf("%v\n", 'a') 128 | printf("%v\n", printable) 129 | 130 | } 131 | 132 | fn main() { 133 | test() 134 | } 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /tests/typeeq.um: -------------------------------------------------------------------------------- 1 | type ( 2 | P1 = ^S1 3 | S1 = struct { 4 | x: int 5 | next: P1 6 | } 7 | ) 8 | 9 | type ( 10 | P2 = ^S2 11 | S2 = struct { 12 | x: int 13 | next: P2 14 | } 15 | ) 16 | 17 | type ( 18 | P3 = ^S3 19 | P4 = ^S4 20 | 21 | S3 = struct { 22 | x: int 23 | next: P4 24 | } 25 | 26 | S4 = struct { 27 | x: int 28 | next: P3 29 | } 30 | ) 31 | 32 | fn test*() { 33 | var ( 34 | s1: S1 35 | s2: S2 36 | s3: S3 37 | s4: S4 38 | 39 | p1: any = s1 40 | p2: any = s2 41 | p3: any = s3 42 | p4: any = s4 43 | ) 44 | 45 | if q1, q2 := P1(p1), P2(p1); q1 == null || q2 != null { 46 | exit(1, "Test failed") 47 | } 48 | 49 | if q3, q4 := P3(p3), P4(p3); q3 == null || q4 != null { 50 | exit(1, "Test failed") 51 | } 52 | 53 | printf(" ...passed\n"); 54 | } 55 | 56 | fn main() { 57 | test() 58 | } 59 | -------------------------------------------------------------------------------- /tests/typeswitch.um: -------------------------------------------------------------------------------- 1 | fn foo(as: ..any) { 2 | for _, a in as { 3 | switch v := type(a) { 4 | case int: printf("int: %d + 5 = %d\n", v, v + 5) 5 | case str: printf("str: %s + 5 = %s\n", v, v + "5") 6 | case []real: printf("[]real: %v + [5] = %v\n", v, append(copy(v), 5)) 7 | default: printf("unknown: %v\n", a) 8 | } 9 | } 10 | } 11 | 12 | fn bar(as: ..any) { 13 | for _, a in as { 14 | switch v := type(a) { 15 | case ^int: v^ += 5 16 | case ^str: v^ += "5" 17 | case ^[]real: v^ = append(v^, 5.0) 18 | default: printf("unknown: %v\n", a) 19 | } 20 | } 21 | } 22 | 23 | fn test*() { 24 | a := 42 25 | b := "42" 26 | c := []real{42} 27 | d := 42.0 28 | 29 | foo(a, b, c, d) 30 | printf("\n") 31 | 32 | bar(&a, &b, &c, &d) 33 | printf("\n") 34 | 35 | foo(&a, &b, &c, &d) 36 | printf("\n") 37 | } 38 | 39 | fn main() { 40 | test() 41 | } -------------------------------------------------------------------------------- /tests/untypedlit.um: -------------------------------------------------------------------------------- 1 | type T = [2]int 2 | 3 | fn foo(x: [3]real, y:[]T, z: struct {w, h: int}, v: map[[2]int][]str, w: [3]int = {3, 8, 14}): ([]real, bool, [2]str) { 4 | printf("%v\n", x) 5 | printf("%v\n", y) 6 | printf("%v\n", z) 7 | printf("%v\n", v) 8 | printf("%v\n", w) 9 | 10 | return {x[0], x[1]}, v[{5, 7}][1] == "World", {"Meow", "Moo"} 11 | } 12 | 13 | fn bar(a: T): [3]int { 14 | var b: T = {2, 3} 15 | var c: T 16 | c = {a[0] + b[0], a[1] + b[1]} 17 | return {42, c[0], c[1]} 18 | } 19 | 20 | fn baz(): [][]int { 21 | var a, b: [2]int = {3, 6}, {5, 7} 22 | return {a, b} 23 | } 24 | 25 | fn test*() { 26 | var ( 27 | p: []str 28 | q, q0: []real 29 | r, r0: bool 30 | s, s0: []str 31 | t: struct {w, h: int} 32 | ) 33 | 34 | q0, r0, s0 = foo({2, 4, -3.14}, {{12, 13}, {44, 47}, {0, -6}}, {200, 100}, {{3, 7}: {}, {5, 7}: {"Hello", "World"}, {11, 3}: {"Psst!"}}) 35 | 36 | p, q, r, s, t = {"Haha", "Hoho"}, q0, r0, s0, {w: 300, h: 400} 37 | 38 | printf("%v\n", p) 39 | printf("%v\n", q) 40 | printf("%v\n", r) 41 | printf("%v\n", s) 42 | printf("%v\n", t) 43 | 44 | u := bar({7, 8}) 45 | 46 | printf("%v\n", u) 47 | 48 | printf("%v\n", baz()) 49 | } 50 | 51 | fn main() { 52 | test() 53 | } -------------------------------------------------------------------------------- /tests/utf8test.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "std.um" 3 | "utf8.um" 4 | ) 5 | 6 | fn testStr(s: str) { 7 | printf("string: %s\n", s) 8 | printf("bytes: %lld\ncharacters: %lld\n", len(s), utf8::runeCount(s)) 9 | 10 | runes := utf8::decode(s) 11 | for _, r in runes { 12 | printf("%s: U+%x\n", r.encode(), r) 13 | } 14 | 15 | s1 := utf8::encode(runes) 16 | std::assert(s1 == s, "UTF-8 encoding failed") 17 | 18 | printf("reconstructed string: %s\n", s1) 19 | printf("\n") 20 | } 21 | 22 | fn test*() { 23 | testStr("▀€$¢") 24 | testStr("Привет, мир!") 25 | testStr("Hello, 世界") 26 | } 27 | 28 | fn main() { 29 | test() 30 | } 31 | -------------------------------------------------------------------------------- /tests/utf8test2.um: -------------------------------------------------------------------------------- 1 | import ( 2 | "std.um" 3 | "utf8.um" 4 | ) 5 | 6 | fn readall(name: str): str { 7 | f, err := std::fopen(name, "rb") 8 | std::exitif(err) 9 | data, err := std::freadall(f) 10 | std::exitif(err) 11 | std::fclose(f) 12 | 13 | return str(data) 14 | } 15 | 16 | fn test*() { 17 | s := readall("utf8test2.txt") 18 | 19 | runes := utf8::decode(s) 20 | s1 := utf8::encode(runes) 21 | 22 | if s1 == s && len(s) > 30000 && len(runes) > 20000 { 23 | printf("Test passed\n") 24 | } else { 25 | printf("Test failed\n") 26 | } 27 | } 28 | 29 | fn main() { 30 | test() 31 | } -------------------------------------------------------------------------------- /tests/vararg.um: -------------------------------------------------------------------------------- 1 | fn printMsg(msg: str, values: ..any) { 2 | valStr := "" 3 | for _, value in values { 4 | valStr += sprintf("%v ", value) 5 | } 6 | printf(msg + " " + valStr + '\n') 7 | } 8 | 9 | fn printPrompt(msg: str, values: ..any) { 10 | printMsg(">> " + msg, values) 11 | } 12 | 13 | fn sum(xs: []real): real { 14 | s := 0.0 15 | for _, x in xs {s += x} 16 | return s 17 | } 18 | 19 | fn mean(xs: ..real): real { 20 | n := len(xs) 21 | if n == 0 {return 0.0} 22 | return sum(xs) / n 23 | } 24 | 25 | type T = struct { 26 | data: str 27 | } 28 | 29 | fn (t: ^T) join(strings: ..str): T { 30 | for _, string in strings { 31 | t.data += string 32 | } 33 | return t^ 34 | } 35 | 36 | fn test*() { 37 | printPrompt("expected ", 12, "Hello World", []bool{true, false, true, true}) 38 | printPrompt("should work with no values") 39 | 40 | printMsg("Four averages:", mean(5.8, 2.4, 7.5), mean(3.14), mean(), mean(-17, 15)) 41 | 42 | var t: T 43 | printMsg("Greeting", t.join(" Hello", " World"), t.join(" Salut le Monde")) 44 | } 45 | 46 | fn main() { 47 | test() 48 | } -------------------------------------------------------------------------------- /tests/vet.um: -------------------------------------------------------------------------------- 1 | 2 | fn main() { 3 | thisFunctionIsNonsense() 4 | } 5 | -------------------------------------------------------------------------------- /tests/weakptr.um: -------------------------------------------------------------------------------- 1 | fn printw(w: weak ^int) { 2 | if q := ^int(w); q != null { 3 | printf("%v\n", q^) 4 | } else { 5 | printf("it's null\n") 6 | } 7 | } 8 | 9 | fn test1() { 10 | printf("Test 1\n") 11 | 12 | var w: weak ^int 13 | { 14 | p := new(int) 15 | p^ = 42 16 | w = p 17 | printw(w) 18 | } 19 | 20 | printw(w) 21 | } 22 | 23 | fn test2() { 24 | printf("Test 2\n") 25 | 26 | type ( 27 | S = struct {x: int; t: ^T} 28 | T = struct {x: int; s: weak ^S} 29 | ) 30 | 31 | p := new(S) 32 | q := new(T) 33 | p.t = q 34 | p.x = 12 35 | q.s = p 36 | q.x = 13 37 | 38 | printf("%v %v\n", p.t.x, ^S(q.s).x) 39 | printf("%v %v\n", p.t.s == p, p == p.t.s) 40 | } 41 | 42 | fn test*() { 43 | test1() 44 | test2() 45 | } 46 | 47 | fn main() { 48 | test() 49 | } 50 | 51 | -------------------------------------------------------------------------------- /tests/weakptr2.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | fn f(p: ^int): int {return p^} 4 | 5 | fn test1() { 6 | x := new(int, 42) 7 | var w: weak ^int = x 8 | printf("%v\n", f(w)) 9 | printf("%v\n", w^) 10 | 11 | w^ = 666 12 | printf("%v\n", w^) 13 | printf("%v\n", weak ^int(x)^) 14 | 15 | weak ^int(x)^ = 2024 16 | printf("%v\n\n", w^) 17 | } 18 | 19 | fn test2() { 20 | x := new([2]int, {5, 7}) 21 | var w: weak ^[2]int = x 22 | printf("%v\n", w^) 23 | 24 | w[1] = 8 25 | printf("%v %v\n", w[0], w[1]) 26 | printf("%v\n", weak ^[2]int(x)^) 27 | 28 | weak ^[2]int(x)^ = {2024, 2025} 29 | 30 | for _, e^ in w { 31 | e^++ 32 | } 33 | 34 | printf("%v\n\n", w^) 35 | } 36 | 37 | type S = struct {a, b: int} 38 | 39 | fn (s: ^S) sq(): int {return s.a * s.a + s.b * s.b} 40 | 41 | fn test3() { 42 | x := &S{5, 7} 43 | var w: weak ^S = x 44 | printf("%v\n", w^) 45 | printf("%v\n\n", w.sq()) 46 | 47 | w.b = 8 48 | printf("%v %v\n", w.a, w.b) 49 | printf("%v\n", weak ^S(x)^) 50 | 51 | weak ^S(x)^ = {2024, 2025} 52 | printf("%v\n\n", w^) 53 | } 54 | 55 | type F = fn(x: int): int 56 | 57 | fn test4() { 58 | var w: weak ^F = &F{return x * x} 59 | printf("%v\n\n", w(5)) 60 | } 61 | 62 | fn test5() { 63 | var w: weak ^int 64 | 65 | { 66 | x := new(int, 42) 67 | w = x 68 | 69 | std::assert(w != null) 70 | std::assert(null != w) 71 | 72 | std::assert(w == x) 73 | std::assert(x == w) 74 | } 75 | 76 | std::assert(w == null) 77 | std::assert(null == w) 78 | } 79 | 80 | fn test*() { 81 | test1() 82 | test2() 83 | test3() 84 | test4() 85 | test5() 86 | } 87 | 88 | fn main() { 89 | test() 90 | } -------------------------------------------------------------------------------- /tests/weakptr3.um: -------------------------------------------------------------------------------- 1 | import "std.um" 2 | 3 | x := 666 4 | var p: ^int 5 | 6 | fn test*() { 7 | p = new(int, 42) 8 | printf("%v\n", weak ^int(p)^) 9 | 10 | p = &x 11 | printf("%v\n", weak ^int(p)^) 12 | } 13 | 14 | fn main() { 15 | test() 16 | } -------------------------------------------------------------------------------- /umbox_post_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf umka_linux umka_windows_mingw 4 | rm -f umka_api.h libumka.so libumka.dll umka umka.exe libumka_static_windows.a libumka_static_linux.a 5 | -------------------------------------------------------------------------------- /umbox_pre_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./build_linux.sh 4 | ./build_linux_mingw.sh 5 | 6 | cp umka_linux/umka . 7 | cp umka_linux/libumka.so . 8 | cp umka_linux/libumka_static_linux.a . 9 | 10 | cp umka_windows_mingw/umka.exe . 11 | cp umka_windows_mingw/libumka.dll . 12 | cp umka_windows_mingw/libumka_static_windows.a . 13 | 14 | cp src/umka_api.h . 15 | --------------------------------------------------------------------------------