├── .travis.yml ├── ACME-Bare-Metal ├── Changes ├── MANIFEST ├── Makefile.PL ├── Metal.xs ├── README ├── lib │ └── ACME │ │ └── Bare │ │ └── Metal.pm ├── ppport.h └── t │ └── ACME-Bare-Metal.t ├── COPYING.txt ├── Makefile ├── README.md ├── TODO ├── compiler ├── Makefile ├── elymas.ey ├── elymasAsm.ey ├── elymasAsmLib.ey ├── elymasAsmOps.ey ├── elymasGlobal.ey ├── elymasGlobalStr.ey ├── elymasGlobalSys.ey ├── elymasGlobalSysAsm.ey ├── elymasGlobalSysDyn.ey ├── elymasGlobalSysOpt.ey ├── elymasGlobalSysTyped.ey ├── elymasLexer.ey ├── elymasTokenize.ey ├── standard.ey └── standardClient.ey ├── doc ├── container.md ├── conventions.md ├── coroutines.md ├── err.md ├── execution.md ├── ffi.md ├── global.md ├── notes ├── parsing.md ├── quoting.md ├── scopes.md ├── server.md ├── sys.md └── tutorial.md ├── elymas.svg ├── elymas ├── Makefile ├── interpreter.ey ├── lib │ ├── bin.ey │ ├── crypt.ey │ ├── err.ey │ ├── ffi.ey │ ├── ffi │ │ ├── gl.ey │ │ ├── gtk.ey │ │ ├── pq.ey │ │ └── sdl.ey │ ├── list.ey │ ├── map.ey │ ├── math.ey │ ├── net.ey │ ├── net │ │ ├── alg.ey │ │ ├── alg │ │ │ ├── http.ey │ │ │ ├── server.ey │ │ │ └── uri.ey │ │ ├── dns.ey │ │ ├── tcp.ey │ │ └── udp.ey │ ├── parser.ey │ ├── sort.ey │ ├── sys.ey │ ├── sys │ │ ├── asmroutines.ey │ │ ├── linux.ey │ │ ├── opt.ey │ │ ├── optroutines.ey │ │ └── so.ey │ ├── tree.ey │ ├── txt.ey │ ├── utf8.ey │ ├── util.ey │ ├── wrapper.ey │ └── xml.ey ├── loaded.ey ├── memdump.ey ├── optimized.ey ├── ptracePerf │ └── perf.ey ├── shared.ey └── tree.test ├── examples ├── compiler-missing.sh ├── non-working │ ├── cross.ey │ ├── freeze.ey │ └── scopeweird.ey ├── regressions │ └── 000001.ey ├── working-compiler │ ├── abstract-right.test │ ├── apply.test │ ├── array-assign.test │ ├── array-list.test │ ├── arraycat.test │ ├── arrays.test │ ├── asm.test │ ├── auto_loop.test │ ├── bor.test │ ├── cat.test │ ├── complex-exec.test │ ├── concat.test │ ├── coroutine.test │ ├── coroutine2.test │ ├── coroutine3.test │ ├── coroutine4.test │ ├── curry-std.test │ ├── curry.test │ ├── deffd.test │ ├── defvs.test │ ├── dom.test │ ├── dom2.test │ ├── each.test │ ├── elymas.ey │ ├── elymasAsm.ey │ ├── elymasAsmLib.ey │ ├── elymasGlobal.ey │ ├── elymasLexer.ey │ ├── exec.test │ ├── fib.test │ ├── fold.test │ ├── freeze.test │ ├── freeze2.test │ ├── grammar-pre.test │ ├── grep-fast.test │ ├── grep.test │ ├── hash-set.test │ ├── include-and-macro.ey │ ├── include-and-macro.inc │ ├── include.test │ ├── int.test │ ├── io.test │ ├── keys.ey │ ├── len.test │ ├── list-spell.ey │ ├── lookup-constant.ey │ ├── lookup-dynamic.ey │ ├── lookup-static.ey │ ├── loop.test │ ├── member-functions.test │ ├── postgresql.test │ ├── qsort.test │ ├── range.test │ ├── regex.test │ ├── remaining-stack.ey │ ├── reverse.test │ ├── run_once.test │ ├── scope-emulation.test │ ├── scope-emulation2.test │ ├── scope-macro.test │ ├── scope.test │ ├── scoping.test │ ├── stackobjects.test │ ├── stackops.test │ ├── standard.ey │ ├── str.test │ ├── strcat.test │ ├── streq_autoloop.test │ ├── string.test │ ├── stringassign.test │ ├── stringexec.test │ ├── syscall.test │ ├── ternary.test │ ├── testing.test │ ├── unclean-macro.test │ └── undefined-resolution.test ├── working-loaded │ ├── bufferedServer.test │ ├── catstrarray.ey │ ├── error.test │ ├── httpServer.test │ ├── interactive-stack.test │ ├── lib │ ├── list.test │ ├── mapping.test │ ├── parser.test │ ├── sha512.test │ ├── sort.test │ ├── wrapper.test │ ├── xml.test │ └── xml.test.xml ├── working-shared │ ├── gtk.ey │ └── sdl.ey └── working │ ├── abstract-right.ey │ ├── array-assign.ey │ ├── array-list.ey │ ├── arraycat.ey │ ├── arraylimits.ey │ ├── arrays.ey │ ├── asm.ey │ ├── bor.ey │ ├── cat.ey │ ├── complex-exec.ey │ ├── concat.ey │ ├── dom.ey │ ├── each.ey │ ├── exec.ey │ ├── fib.ey │ ├── fold.ey │ ├── grep.ey │ ├── hash-set.ey │ ├── include.ey │ ├── int.ey │ ├── io.ey │ ├── len.ey │ ├── loop.ey │ ├── macro.ey │ ├── qsort.ey │ ├── range.ey │ ├── recursion.ey │ ├── regex.ey │ ├── reverse.ey │ ├── scope.ey │ ├── scoping.ey │ ├── stackops.ey │ ├── strcat.ey │ ├── streq_autoloop.ey │ ├── string.ey │ ├── suspend.ey │ ├── syscall.ey │ ├── testing.ey │ └── unscoped-function.ey ├── interpreter ├── Elymas.pm ├── ElymasAsm.pm ├── ElymasGlobal.pm ├── ElymasLinux.pm ├── ElymasSys.pm ├── Makefile └── elymas └── support └── elymas.vim /.travis.yml: -------------------------------------------------------------------------------- 1 | language: perl 2 | perl: 3 | - "5.24" 4 | 5 | install: true 6 | 7 | script: 8 | - make 9 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/Changes: -------------------------------------------------------------------------------- 1 | Revision history for Perl extension ACME::Bare::Metal. 2 | 3 | 0.01 Sat Dec 22 18:15:04 2012 4 | - original version; created by h2xs 1.23 with options 5 | -A -n ACME::Bare::Metal 6 | 7 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/MANIFEST: -------------------------------------------------------------------------------- 1 | Changes 2 | Makefile.PL 3 | MANIFEST 4 | Metal.xs 5 | ppport.h 6 | README 7 | t/ACME-Bare-Metal.t 8 | lib/ACME/Bare/Metal.pm 9 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/Makefile.PL: -------------------------------------------------------------------------------- 1 | use 5.014002; 2 | use ExtUtils::MakeMaker; 3 | # See lib/ExtUtils/MakeMaker.pm for details of how to influence 4 | # the contents of the Makefile that is written. 5 | WriteMakefile( 6 | NAME => 'ACME::Bare::Metal', 7 | VERSION_FROM => 'lib/ACME/Bare/Metal.pm', # finds $VERSION 8 | PREREQ_PM => {}, # e.g., Module::Name => 1.1 9 | ($] >= 5.005 ? ## Add these new keywords supported since 5.005 10 | (ABSTRACT_FROM => 'lib/ACME/Bare/Metal.pm', # retrieve abstract from module 11 | AUTHOR => 'A. U. Thor ') : ()), 12 | LIBS => [''], # e.g., '-lm' 13 | DEFINE => '', # e.g., '-DHAVE_SOMETHING' 14 | INC => '-I.', # e.g., '-I. -I/usr/include/other' 15 | # Un-comment this if you add C files to link with later: 16 | # OBJECT => '$(O_FILES)', # link all the C files too 17 | ); 18 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/Metal.xs: -------------------------------------------------------------------------------- 1 | #include "EXTERN.h" 2 | #include "perl.h" 3 | #include "XSUB.h" 4 | 5 | #include "ppport.h" 6 | #include 7 | 8 | 9 | MODULE = ACME::Bare::Metal PACKAGE = ACME::Bare::Metal 10 | 11 | void * 12 | allocate(length) 13 | int length 14 | CODE: 15 | RETVAL = mmap(0, length, PROT_EXEC | PROT_READ | PROT_WRITE, 16 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 17 | OUTPUT: 18 | RETVAL 19 | 20 | void * 21 | allocateAt(length, addr) 22 | int length 23 | void *addr 24 | CODE: 25 | RETVAL = mmap(addr, length, PROT_EXEC | PROT_READ | PROT_WRITE, 26 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 27 | OUTPUT: 28 | RETVAL 29 | 30 | void 31 | deallocate(block, length) 32 | void *block 33 | int length 34 | CODE: 35 | munmap(block, length); 36 | 37 | void 38 | poke(addr, data) 39 | void *addr 40 | int data 41 | CODE: 42 | *((unsigned char *)addr) = (unsigned char)data; 43 | 44 | int 45 | peek(addr) 46 | void *addr 47 | CODE: 48 | unsigned char buf = *(unsigned char *)addr; 49 | RETVAL = buf; 50 | OUTPUT: 51 | RETVAL 52 | 53 | void 54 | execute(block) 55 | void *block 56 | CODE: 57 | ((void (*)(void))block)(); 58 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/README: -------------------------------------------------------------------------------- 1 | ACME-Bare-Metal version 0.01 2 | ============================ 3 | 4 | The README is used to introduce the module and provide instructions on 5 | how to install the module, any machine dependencies it may have (for 6 | example C compilers and installed libraries) and any other information 7 | that should be provided before the module is installed. 8 | 9 | A README file is required for CPAN modules since CPAN extracts the 10 | README file from a module distribution so that people browsing the 11 | archive can use it get an idea of the modules uses. It is usually a 12 | good idea to provide version information here so that people can 13 | decide whether fixes for the module are worth downloading. 14 | 15 | INSTALLATION 16 | 17 | To install this module type the following: 18 | 19 | perl Makefile.PL 20 | make 21 | make test 22 | make install 23 | 24 | DEPENDENCIES 25 | 26 | This module requires these other modules and libraries: 27 | 28 | blah blah blah 29 | 30 | COPYRIGHT AND LICENCE 31 | 32 | Put the correct copyright and licence information here. 33 | 34 | Copyright (C) 2012 by A. U. Thor 35 | 36 | This library is free software; you can redistribute it and/or modify 37 | it under the same terms as Perl itself, either Perl version 5.14.2 or, 38 | at your option, any later version of Perl 5 you may have available. 39 | 40 | 41 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/lib/ACME/Bare/Metal.pm: -------------------------------------------------------------------------------- 1 | package ACME::Bare::Metal; 2 | 3 | use 5.014002; 4 | use strict; 5 | use warnings; 6 | 7 | require Exporter; 8 | 9 | our @ISA = qw(Exporter); 10 | 11 | # Items to export into callers namespace by default. Note: do not export 12 | # names by default without a very good reason. Use EXPORT_OK instead. 13 | # Do not simply export all your public functions/methods/constants. 14 | 15 | # This allows declaration use ACME::Bare::Metal ':all'; 16 | # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK 17 | # will save memory. 18 | our %EXPORT_TAGS = ( 'all' => [ qw( 19 | 20 | ) ] ); 21 | 22 | our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); 23 | 24 | our @EXPORT = qw( 25 | 26 | ); 27 | 28 | our $VERSION = '0.01'; 29 | 30 | require XSLoader; 31 | XSLoader::load('ACME::Bare::Metal', $VERSION); 32 | 33 | # Preloaded methods go here. 34 | 35 | 1; 36 | __END__ 37 | # Below is stub documentation for your module. You'd better edit it! 38 | 39 | =head1 NAME 40 | 41 | ACME::Bare::Metal - Perl extension for blah blah blah 42 | 43 | =head1 SYNOPSIS 44 | 45 | use ACME::Bare::Metal; 46 | blah blah blah 47 | 48 | =head1 DESCRIPTION 49 | 50 | Stub documentation for ACME::Bare::Metal, created by h2xs. It looks like the 51 | author of the extension was negligent enough to leave the stub 52 | unedited. 53 | 54 | Blah blah blah. 55 | 56 | =head2 EXPORT 57 | 58 | None by default. 59 | 60 | 61 | 62 | =head1 SEE ALSO 63 | 64 | Mention other useful documentation such as the documentation of 65 | related modules or operating system documentation (such as man pages 66 | in UNIX), or any relevant external documentation such as RFCs or 67 | standards. 68 | 69 | If you have a mailing list set up for your module, mention it here. 70 | 71 | If you have a web site set up for your module, mention it here. 72 | 73 | =head1 AUTHOR 74 | 75 | A. U. Thor, Edrahflow@E 76 | 77 | =head1 COPYRIGHT AND LICENSE 78 | 79 | Copyright (C) 2012 by A. U. Thor 80 | 81 | This library is free software; you can redistribute it and/or modify 82 | it under the same terms as Perl itself, either Perl version 5.14.2 or, 83 | at your option, any later version of Perl 5 you may have available. 84 | 85 | 86 | =cut 87 | -------------------------------------------------------------------------------- /ACME-Bare-Metal/t/ACME-Bare-Metal.t: -------------------------------------------------------------------------------- 1 | # Before `make install' is performed this script should be runnable with 2 | # `make test'. After `make install' it should work as `perl ACME-Bare-Metal.t' 3 | 4 | ######################### 5 | 6 | # change 'tests => 1' to 'tests => last_test_to_print'; 7 | 8 | use strict; 9 | use warnings; 10 | 11 | use Test::More tests => 5; 12 | BEGIN { use_ok('ACME::Bare::Metal') }; 13 | 14 | ######################### 15 | 16 | # Insert your test code below, the Test::More module is use()ed here so read 17 | # its man page ( perldoc Test::More ) for help writing this test script. 18 | 19 | my $block = ACME::Bare::Metal::allocate(4096); 20 | ok($block > 0, "Block allocation"); 21 | 22 | ACME::Bare::Metal::poke($block, 0xC3); 23 | ok(ACME::Bare::Metal::peek($block) == 0xC3); 24 | 25 | ACME::Bare::Metal::execute($block); 26 | ACME::Bare::Metal::deallocate($block, 4096); 27 | 28 | $block = ACME::Bare::Metal::allocateAt(4096, 0x0000700000000000); 29 | ok($block > 0, "Block allocation"); 30 | 31 | ACME::Bare::Metal::poke($block, 0xC3); 32 | ok(ACME::Bare::Metal::peek($block) == 0xC3); 33 | 34 | ACME::Bare::Metal::execute($block); 35 | ACME::Bare::Metal::deallocate($block, 4096); 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: elymas/loaded elymas/shared 2 | 3 | elymas/loaded elymas/shared: elymas/interpreter $(shell find elymas/ -name '*.ey' ) 4 | cd elymas && $(MAKE) 5 | 6 | elymas/interpreter: elymas/interpreter.ey compiler/*.ey interpreter/Metal.so interpreter/ACME 7 | cd compiler && \ 8 | ../interpreter/elymas elymas.ey ../elymas/interpreter.ey 9 | mv -v compiler/interpreter $@ 10 | 11 | interpreter/Metal.so interpreter/ACME: 12 | cd ACME-Bare-Metal/ && \ 13 | perl Makefile.PL && \ 14 | $(MAKE) 15 | cd interpreter && \ 16 | ln -vs ../ACME-Bare-Metal/blib/arch/auto/ACME/Bare/Metal/Metal.so . && \ 17 | ln -vs ../ACME-Bare-Metal/lib/ACME ACME 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Elymas logo 2 | 3 | *Just because I'm not following the true path, doesn't mean I can't get it to work.* 4 | 5 | [![Build Status](https://travis-ci.org/Drahflow/Elymas.svg?branch=master)](https://travis-ci.org/Drahflow/Elymas) 6 | 7 | Examples 8 | -------- 9 | 10 | A programming language... 11 | 12 | 1 dump 13 | # 0000000000000001 14 | 15 | ... stack based programming language ... 16 | 17 | 1 2 add dump 18 | # 0000000000000003 19 | 20 | ... with array support ... 21 | 22 | [ 1 2 ] dump 23 | # [ 24 | # 0000000000000001 25 | # 0000000000000002 26 | # ] 27 | 28 | ... did I mention array support ... 29 | 30 | 2 [ 1 2 ] add dump 31 | [ 0 1 ] [ 1 2 ] add dump 32 | # [ 33 | # 0000000000000003 34 | # 0000000000000004 35 | # ] 36 | # [ 37 | # 0000000000000001 38 | # 0000000000000003 39 | # ] 40 | 41 | ... user definable functions ... 42 | 43 | { 2 add } /addTwo deffst 44 | 1 addTwo dump 45 | # 0000000000000003 46 | 47 | ... variables ... 48 | 49 | 2 ==two 50 | 1 two add dump 51 | # 0000000000000003 52 | 53 | ... function objects ... 54 | 55 | { { 2 add } } /returnAddTwo deffst 56 | returnAddTwo /addTwo deffst 57 | 1 addTwo dump 58 | # 0000000000000003 59 | 60 | ... closures ... 61 | 62 | { 2 ==two { two add } } /returnAddTwo deffst 63 | returnAddTwo /addTwo deffst 64 | 1 addTwo dump 65 | # 0000000000000003 66 | 67 | ... structured data types ... 68 | 69 | < 70 | 1 ==one 71 | 2 ==two 72 | > ==struct 73 | 74 | struct keys dump 75 | struct .two dump 76 | 77 | # [ 78 | # "one" 79 | # "two" 80 | # ] 81 | # 0000000000000002 82 | 83 | ... and more. 84 | 85 | "Elymas" { "(..)(.*)" regex } |dump loop 86 | 87 | # "El" 88 | # "ym" 89 | # "as" 90 | 91 | 92 | Technical Pecularities 93 | ---------------------- 94 | 95 | * no runtime interpreter, executes real assembly 96 | * same binary both interpretes and compiles 97 | * freeze arbitrary program states to ELF-binaries 98 | * self hosted via `{ "/dev/stdin" include }' "interpreter" sys .freeze` 99 | * yes, this works and generates a stand-alone interpreter/compiler 100 | * bootstraps from perl 101 | * no perl left in final binaries 102 | * macro support 103 | * names carry information about being constant or constantly having the same type each resolution 104 | * just-too-late opcode optimization 105 | * so at least one resolution is guaranteed to have taken place 106 | * can declare names any time before first usage 107 | * assembly optimizer realized as a loadable library 108 | * yes, it does optimize itself while running 109 | * regex-engine written in the language itself 110 | * source includes an assembler for 64bit x86 111 | 112 | 113 | Features 114 | -------- 115 | 116 | * non-braindead stack manipulation, e.g. `-021` specifies "top element, then third, then second" 117 | * concatenative language syntax, e.g. `data modifyOne modifyTwo modifyThree` 118 | * trivial to build DSLs 119 | * compact code 120 | * more readable than APL though 121 | * unless you don't want it to be 122 | * acceptable performance (and you can always switch to assembly if necessary) 123 | * I actually use it for non-trivial projects 124 | 125 | Documentation 126 | ------------- 127 | 128 | Please see [the tutorial](doc/tutorial.md) for an introduction and further documentation. 129 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * better sys .file 2 | * don't make newly opened files executable by default 3 | * make :executable, :nonexecutable, :writable, :readable, etc. 4 | * apply :readwrite by default on :creating 5 | * apply the trace extractor to non-tail situations 6 | * reduze ./optimized binary size (clean up lib/sys/opt.ey code) 7 | * inline trivial functions when optimizer generates ... /rax :movqImmReg /rax :callqReg sequence 8 | * parse }" created constant pushers into PUSH in optimizer 9 | * hunt the }"s down 10 | * don't allocate ints for syscalls if not necessary 11 | * *THISSCOPE could also work with PUSH 12 | * handle huge objects better (and move them out of linear heap space) 13 | * make map work on non-strings, too 14 | * utf8 15 | * regex substitution 16 | * [,] must be escapable in regex 17 | * regex engine still only 10% as fast during scanning as perl 18 | * txt .consume .u sollte nicht negative Zahlen liefern 19 | * evtl. BigNums bauen und die Int-Funktionen entsprechend machen 20 | * trigonometrics 21 | * create sys .posix 22 | * port the sys functions to FreeBSD 23 | * stack traces with function source 24 | * make it possible to put comments into the stacktrace for iteration over non-uniform objects 25 | 26 | * testsuite (incl. coverage test) 27 | * what is broken with working-loaded/sort.test 28 | 29 | * make '' applicable to arrays, too, i.e. save input type 30 | 31 | * consider polymorphic call-site caches instead of deffs_t_ / deffs? 32 | 33 | * eliminate all FIXMEs 34 | * stack underflow protection 35 | * input prompt 36 | * better interactive error handling when interpreting from stdin 37 | * document ALL THE LIBRARIES 38 | * consider https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system and finally make the stuff typed correctly 39 | 40 | * on fatal resolution failure, try parent scopes to see whether it's a simple typo (levenstein) 41 | 42 | * Why is `parse quartfull` in igor taking significant time? Java LR(0) parser allegedly takes 0.001s. 43 | -------------------------------------------------------------------------------- /compiler/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | 3 | CASES=../examples/working-compiler 4 | EXE=../../compiler/elymas.ey 5 | ABSTRACT=s/00006[0-9A-F]\{11\}//g;s/00007[0-9A-F]\{11\}//g;s/00002[0-9A-F]\{11\}//g;s/ ........//g 6 | 7 | test: 8 | for f in $$(ls $(CASES)/*.test | sed -e 's/.*\///g'); do \ 9 | printf "%20s: " $$f; \ 10 | echo Input | ( cd $(CASES); $(EXE) "$$f"; echo ) \ 11 | 2> "test/$$f.err.test" | sed -e '$(ABSTRACT)' > "test/$$f.test"; \ 12 | if diff "test/$$f.test" "test/$$f.correct" && diff "test/$$f.err.test" "test/$$f.err.correct"; then \ 13 | echo "Success."; \ 14 | else \ 15 | echo "Failed."; \ 16 | fi \ 17 | done 18 | 19 | generate-test: 20 | mkdir -p test 21 | for f in $$(ls $(CASES)/*.test | sed -e 's/.*\///g'); do \ 22 | echo $$f; \ 23 | echo Input | ( cd $(CASES); $(EXE) "$$f"; echo ) \ 24 | 2> "test/$$f.err.correct" | sed -e '$(ABSTRACT)' | tee "test/$$f.correct"; \ 25 | sleep 1; \ 26 | done 27 | 28 | generate-test-fast: 29 | mkdir -p test 30 | for f in $$(ls $(CASES)/*.test | sed -e 's/.*\///g'); do \ 31 | echo $$f; \ 32 | echo Input | ( cd $(CASES); $(EXE) "$$f"; echo ) \ 33 | 2> "test/$$f.err.correct" | sed -e '$(ABSTRACT)' | tee "test/$$f.correct"; \ 34 | done 35 | -------------------------------------------------------------------------------- /compiler/elymas.ey: -------------------------------------------------------------------------------- 1 | #!/home/drahflow/elymas/interpreter/elymas 2 | 3 | "standard.ey" include 4 | 5 | 1 ==ASSERTIONS 6 | 7 | "elymasGlobal.ey" include 8 | "elymasTokenize.ey" include 9 | "elymasLexer.ey" include 10 | 11 | sys .argv len not { "Usage: ./elymas " die } rep 12 | 13 | [ 14 | "standard.ey" 15 | "standardClient.ey" 16 | "elymasTokenize.ey" 17 | 0 sys .argv * 18 | ] { 19 | sys .file -0010 .open 20 | executeFile 21 | .close 22 | } each 23 | 24 | # vim: syn=elymas 25 | -------------------------------------------------------------------------------- /compiler/elymasAsm.ey: -------------------------------------------------------------------------------- 1 | < 2 | 4096 ==PAGESIZE 3 | 4096 16 mul 8 mul ==STACKSIZE 4 | 65536 ==GLOBALALLOCSSIZE 5 | 16 ==STACKSTART 6 | 7 | 6148914691236517205 ==STACKBOTTOMMARKER 8 | 6148914691236517206 ==STACKTOPMARKER 9 | 4 ==ERRORMARKER 10 | 3 ==HASHPOSITIONS # number of positions to probe on collisions 11 | 12 | # hex decoding 13 | { 14 | 0 -01 { "(.)(.*)" regex } { 15 | { 16 mul } 16 | { { eq }_ [ "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F" ] -01 index add } 17 | -41*20*3 18 | } loop 19 | } "%" defq 20 | 21 | "elymasAsmOps.ey" include 22 | 23 | # map "anonymous" allocations away from interpreter heap 24 | 25 | 52776558133248 ==miscAllocBase # 0x300000000000 26 | { ==size 27 | size miscAllocBase sys .asm .allocAt 28 | size miscAllocBase add =miscAllocBase 29 | } /alloc deff 30 | 31 | # global alloc list layout 32 | # %0 : next unused byte of global alloc list as an offset from beginning of list 33 | # %8 : 34 | # %10 : base of this very alloc 35 | # %18 : size of this very alloc 36 | # %20... : of next allocs 37 | # This structure is directly read also in sys .asm .programStart 38 | < 39 | { # ==addr 40 | [ -01 7 add 8 { _ sys .asm .peek -01 1 sub } rep -- ] { -01 256 mul add } fold 41 | } /peekImm64 deff 42 | 43 | { ==addr ==value 44 | [ value imm64 ] { addr sys .asm .poke addr 1 add =addr } each 45 | } /pokeImm64 deff 46 | 47 | GLOBALALLOCSSIZE alloc ==allocs 48 | allocs .base ==i 49 | [ 50 | %20 imm64 51 | 0 imm64 52 | allocs .base imm64 53 | allocs .size imm64 54 | ] { i sys .asm .poke i 1 add =i } each 55 | 56 | { ==block 57 | allocs .base peekImm64 ==nextOffset 58 | nextOffset 16 add _ 59 | GLOBALALLOCSSIZE gt { "Global allocation list full." die } rep 60 | allocs .base pokeImm64 61 | allocs .base nextOffset add =nextOffset 62 | 63 | block .base nextOffset pokeImm64 64 | block .size nextOffset 8 add pokeImm64 65 | } /register deff 66 | 67 | { allocs .base } /base deff 68 | > ==globalAllocations 69 | 70 | # stack layout 71 | # %0 : stack size 72 | # %8 : current stack pointer 73 | # %10 : stack top marker 74 | # ... : real stack 75 | # : stack bottom marker 76 | [ /bootStack /bootCallStack ] { 77 | < 78 | PAGESIZE alloc _ globalAllocations .register 79 | ==stack 80 | stack .base ==i 81 | [ 82 | PAGESIZE imm64 83 | stack .base PAGESIZE add 8 sub imm64 84 | STACKTOPMARKER imm64 85 | ] { i sys .asm .poke i 1 add =i } each 86 | 87 | stack .base PAGESIZE add 8 sub =i 88 | [ 89 | STACKBOTTOMMARKER imm64 90 | ] { i sys .asm .poke i 1 add =i } each 91 | 92 | stack 93 | > -12 == 94 | }' each 95 | 96 | PAGESIZE alloc _ globalAllocations .register 97 | ==:initialCoroutine 98 | 99 | # TODO create a heap-based initial coroutine 100 | < 101 | initialCoroutine .base ==i 102 | [ 103 | 40 0 0 0 0 0 0 %C8 104 | 0 imm64 # no instruction pointer, will be driven via executeOn 105 | 0 imm64 # no scope pointer, will be installed by elymalGlobal into r14 106 | bootCallStack .base imm64 107 | bootStack .base imm64 108 | # 40 bytes so far, coroutine image stops here 109 | # 40-47: original rsp value 110 | 0 imm64 111 | # 48-55: currently running co-routine (so elymasGlobal can switch to heap allocated one) 112 | initialCoroutine .base imm64 113 | ] { i sys .asm .poke i 1 add =i } each 114 | > -- 115 | 116 | STACKSIZE alloc _ globalAllocations .register 117 | .base ==:quoteEncodingBufferCode 118 | 119 | STACKSIZE alloc _ globalAllocations .register 120 | .base ==:quoteEncodingBufferObjects 121 | 122 | { ==opcodes 123 | opcodes len 1 sub PAGESIZE udiv 1 add PAGESIZE mul alloc /codearea defv 124 | sys .asm .|poke =*poke 125 | codearea .base opcodes { -101 poke 1 add } each -- 126 | codearea 127 | } /arrayToCode deff 128 | 129 | # take an array of instruction bytes and execute it in the given coroutine context 130 | { ==opcodes 131 | [ 132 | /rbx pushqReg 133 | /rbp pushqReg 134 | /r12 pushqReg 135 | /r13 pushqReg 136 | /r14 pushqReg 137 | /r15 pushqReg 138 | initialCoroutine .base 40 add /rbx movqImmReg 139 | /rsp /rbx movqRegMem 140 | 141 | initialCoroutine .base 48 add /rbx movqImmReg 142 | /rbx /r13 movqMemReg 143 | 16 /r13 /r14 movqMemDisp8Reg 144 | 24 /r13 /rbx movqMemDisp8Reg 145 | 8 /rbx /r15 movqMemDisp8Reg 146 | 32 /r13 /rbx movqMemDisp8Reg 147 | 8 /rbx /rsp movqMemDisp8Reg 148 | 149 | opcodes _ len dearray 150 | 151 | /r14 16 /r13 movqRegMemDisp8 152 | 24 /r13 /rbx movqMemDisp8Reg 153 | /r15 8 /rbx movqRegMemDisp8 154 | 32 /r13 /rbx movqMemDisp8Reg 155 | /rsp 8 /rbx movqRegMemDisp8 156 | initialCoroutine .base 48 add /rbx movqImmReg 157 | /r13 /rbx movqRegMem 158 | 159 | initialCoroutine .base 40 add /rbx movqImmReg 160 | /rbx /rsp movqMemReg 161 | /r15 popqReg 162 | /r14 popqReg 163 | /r13 popqReg 164 | /r12 popqReg 165 | /rbp popqReg 166 | /rbx popqReg 167 | retn 168 | ] 169 | } /compile deff 170 | 171 | { 172 | compile arrayToCode _ .base sys .asm .execute 173 | .free 174 | } /execute deff 175 | > /assembler defv 176 | 177 | # vim: syn=elymas 178 | -------------------------------------------------------------------------------- /compiler/elymasGlobalSys.ey: -------------------------------------------------------------------------------- 1 | < 2 | "sys" enterSubScope 3 | 4 | < 5 | # handle an identifier in a given scope according to current quote level 6 | # 0 -> scope to execute identifier in 7 | # 1 -> identifier to handle 8 | # 0 <- scope after execution 9 | [[ 10 | 8 /r15 :subqImm8Reg 11 | /r15 :popqMem 12 | 13 | 8 /r15 :subqImm8Reg 14 | /r14 /r15 :movqRegMem 15 | /r14 :popqReg # load scope from argument 16 | 17 | internalExecuteIdentifier /rax :movqImmReg 18 | /rax :callqReg 19 | 20 | /r14 :pushqReg 21 | /r15 /r14 :movqMemReg 22 | 8 /r15 :addqImm8Reg 23 | 24 | /r15 :pushqMem 25 | 8 /r15 :addqImm8Reg 26 | :retn 27 | ]] /eyexecuteIdentifierScoped defv 28 | 29 | # handle an identifier according to current quote level 30 | # 0 -> identifier to handle 31 | [[ 32 | 8 /r15 :subqImm8Reg 33 | /r15 :popqMem 34 | 35 | internalExecuteIdentifier /rax :movqImmReg 36 | /rax :callqReg 37 | 38 | /r15 :pushqMem 39 | 8 /r15 :addqImm8Reg 40 | :retn 41 | ]] /eyexecuteIdentifier defv 42 | 43 | # resolve an identifier in a given scope and return full resolve information 44 | # 0 -> scope to resolve identifier in 45 | # 1 -> identifier to resolve 46 | # 0 <- address of resolved object (0 if nonexistent) 47 | # 1 <- activation mode and constness of element (only present if resolution successful) 48 | # 2 <- memory address of entry (only present if resolution successful) 49 | # 3 <- number of parent pointers followed (only present if resolution successful) 50 | # 4 <- entry index * 8 within scope (only present if resolution successful) 51 | # 5 <- 0 if within scope data area, scope object size if within extension area (only present if resolution successful) 52 | # TODO simplify by returning unboxed ints where appropriate maybe 53 | [[ 54 | 8 /r15 :subqImm8Reg 55 | /r15 :popqMem 56 | 57 | /rdi :popqReg 58 | /rsi :popqReg 59 | 60 | ::internalResolve /rax :movqImmReg 61 | /rax :callqReg 62 | 63 | /rax /rax :andqRegReg 64 | /failure :jzLbl32 65 | 66 | 48 /r15 :subqImm8Reg 67 | /rbp 40 /r15 :movqRegMemDisp8 68 | /rsi 32 /r15 :movqRegMemDisp8 69 | /rdi 24 /r15 :movqRegMemDisp8 70 | /rcx 16 /r15 :movqRegMemDisp8 71 | /rdx 8 /r15 :movqRegMemDisp8 72 | /rax /r15 :movqRegMem 73 | 74 | [ 40 32 24 16 8 0 ] { ==o 75 | ::internalAllocateInteger /rax :movqImmReg 76 | /rax :callqReg 77 | /rax :pushqReg 78 | o /r15 /rdx :movqMemDisp8Reg 79 | /rdx 8 /rax :movqRegMemDisp8 80 | } each 81 | 82 | 48 /r15 :addqImm8Reg 83 | /done :jmpLbl8 84 | 85 | @failure 86 | 87 | ::internalAllocateInteger /rax :movqImmReg 88 | /rax :callqReg 89 | /rax :pushqReg 90 | 0 8 /rax :andqImm8MemDisp8 91 | 92 | @done 93 | 94 | /r15 :pushqMem 95 | 8 /r15 :addqImm8Reg 96 | :retn 97 | ]] /eyresolveInfo defv 98 | 99 | # return information about the captured scope of a function 100 | # 0 -> function object 101 | # 0 <- any scope captured 102 | # 1 <- if any scope was caputered, that scope 103 | [[ 104 | 8 /r15 :subqImm8Reg 105 | /r15 :popqMem 106 | 107 | /rsi :popqReg 108 | 8 /rsi /rsi :movqMemDisp8Reg 109 | /rsi /rsi :testqRegReg 110 | /noScopeCaptured :jzLbl8 111 | 112 | /rsi :pushqReg # push scope 113 | 1 /rax :movqImmReg 114 | 63 /rax :btsqImm8Reg 115 | /rax :pushqReg 116 | 117 | /done :jmpLbl8 118 | 119 | @noScopeCaptured 120 | 63 /rsi :btsqImm8Reg 121 | /rsi :pushqReg 122 | 123 | @done 124 | /r15 :pushqMem 125 | 8 /r15 :addqImm8Reg 126 | :retn 127 | ]] /eycapturedScope defv 128 | > _ ==globalFunctions { defv }' ::allocateOffsetStruct 129 | 130 | [ 131 | globalFunctions keys eydeff { | }' createScopeEntries 132 | createScopeExtensionEntries 133 | ] :execute 134 | 135 | "elymasGlobalSysAsm.ey" include 136 | "elymasGlobalSysOpt.ey" include 137 | "elymasGlobalSysDyn.ey" include 138 | "elymasGlobalSysTyped.ey" include 139 | 140 | [ 141 | { sys .?linux } { "linux" } 142 | { sys .?freebsd } { "freebsd" } 143 | ] conds enterSubScope leaveSubScope 144 | 145 | leaveSubScope 146 | > -- 147 | 148 | # vim: syn=elymas 149 | -------------------------------------------------------------------------------- /compiler/elymasGlobalSysDyn.ey: -------------------------------------------------------------------------------- 1 | # dynamic variables with stack 2 | < 3 | "dyn" enterSubScope 4 | 5 | 5 ==DYNAMICVARIABLEMARKER 6 | 7 | < 8 | # get dynamic variable value 9 | # 0 -> dynamic variable object 10 | # 0 <- non-zero if a value is defined, zero otherwise 11 | # 1 <- current value (if it exists) 12 | [[ 13 | /rbx :popqReg 14 | 15 | /rdx :popqReg 16 | DYNAMICVARIABLEMARKER /rax :movqImmReg 17 | :STACKBOTTOMMARKER /rcx :movqImmReg 18 | /r15 /rsi :movqRegReg 19 | 8 /rsi :subqImm8Reg 20 | 21 | @scanStack 22 | 8 /rsi :addqImm8Reg 23 | 24 | /rsi /rax :cmpqMemReg 25 | /dynamicVariableMarker :jzLbl8 26 | /rsi /rcx :cmpqMemReg 27 | /scanStack :jnzLbl8 28 | 29 | # no value was found 30 | /rax /rax :xorqRegReg 31 | 63 /rax :btsqImm8Reg 32 | /rax :pushqReg 33 | 34 | /rbx :pushqReg 35 | :retn 36 | 37 | @dynamicVariableMarker 38 | 8 /rsi /rdx :cmpqMemDisp8Reg 39 | /scanStack :jnzLbl8 # wrong variable 40 | 41 | 16 /rsi :pushqMemDisp8 42 | /rax /rax :xorqRegReg 43 | /rax :incqReg 44 | 63 /rax :btsqImm8Reg 45 | /rax :pushqReg 46 | 47 | /rbx :pushqReg 48 | :retn 49 | ]] /eyget defv 50 | 51 | # set dynamic variable and execute function 52 | # 0 -> dynamic variable object 53 | # 1 -> value to set 54 | # 2 -> object to execute 55 | [[ 56 | 8 /r15 :subqImm8Reg 57 | /r15 :popqMem 58 | 59 | 24 /r15 :subqImm8Reg 60 | 8 /r15 :popqMemDisp8 61 | 16 /r15 :popqMemDisp8 62 | DYNAMICVARIABLEMARKER /rax :movqImmReg 63 | /rax /r15 :movqRegMem 64 | 65 | |ey* /rax :movqImmReg 66 | /rax :callqReg 67 | 68 | 24 /r15 :addqImm8Reg 69 | /r15 :pushqMem 70 | 8 /r15 :addqImm8Reg 71 | :retn 72 | ]] /eywith defv 73 | > _ ==globalFunctions { defv }' ::allocateOffsetStruct 74 | 75 | [ 76 | globalFunctions keys eydeff { | }' createScopeEntries 77 | createScopeExtensionEntries 78 | ] :execute 79 | 80 | leaveSubScope 81 | > -- 82 | 83 | # vim: syn=elymas 84 | -------------------------------------------------------------------------------- /compiler/elymasGlobalSysOpt.ey: -------------------------------------------------------------------------------- 1 | < 2 | "opt" enterSubScope 3 | 4 | < 5 | # stub 6 | # 0 -> code object 7 | # 1 -> current scope 8 | # 0 <- same code object (if different object, optimization would have taken place) 9 | # 1 <- current scope (value ignored) 10 | [[ 11 | :retn 12 | ]] /eyhook defv 13 | > _ ==globalFunctions { defv }' ::allocateOffsetStruct 14 | 15 | [ 16 | globalFunctions keys eydeff { | }' createScopeEntries 17 | createScopeExtensionEntries 18 | ] :execute 19 | 20 | leaveSubScope 21 | > -- 22 | 23 | # vim: syn=elymas 24 | -------------------------------------------------------------------------------- /compiler/elymasGlobalSysTyped.ey: -------------------------------------------------------------------------------- 1 | < 2 | < 3 | # return the array of input types of a function 4 | # 0 -> the function object to analyze 5 | # 0 <- the array of input types 6 | [[ 7 | /rbx :popqReg 8 | 9 | /rdx :popqReg 10 | 16 /rdx /rdx :movqMemDisp8Reg 11 | /rdx /rdx :testqRegReg 12 | /typed :jnzLbl8 13 | 14 | # untyped functions, it does not officially take any arguments 15 | /rdi /rdi :xorqRegReg 16 | ::internalAllocateArray /rax :movqImmReg 17 | /rax :callqReg 18 | /rax :pushqReg 19 | /rbx :pushqReg 20 | :retn 21 | 22 | @typed 23 | 8 /rdx /rdi :movqMemDisp8Reg 24 | 3 /rdi :shlqImm8Reg 25 | 16 /rdx /rsi :leaqMemDisp8Reg 26 | /rsi :pushqReg 27 | ::internalAllocateArray /rax :movqImmReg 28 | /rax :callqReg 29 | 30 | /rsi :popqReg 31 | /rax :pushqReg 32 | 33 | 8 /rax /rdi :leaqMemDisp8Reg 34 | /rax /ecx :movlMemReg 35 | 8 /rcx :subqImm8Reg 36 | :reprcx :movsb 37 | 38 | /rbx :pushqReg 39 | :retn 40 | ]] /eyinputs defv 41 | 42 | # return the array of output types of a function 43 | # 0 -> the function object to analyze 44 | # 0 <- the array of output types 45 | [[ 46 | /rbx :popqReg 47 | 48 | /rdx :popqReg 49 | 16 /rdx /rdx :movqMemDisp8Reg 50 | /rdx /rdx :testqRegReg 51 | /typed :jnzLbl8 52 | 53 | # untyped functions, it does not officially produce any objects 54 | /rdi /rdi :xorqRegReg 55 | ::internalAllocateArray /rax :movqImmReg 56 | /rax :callqReg 57 | /rax :pushqReg 58 | /rbx :pushqReg 59 | :retn 60 | 61 | @typed 62 | 8 /rdx /rax :movqMemDisp8Reg 63 | 16 8 /rax /rdx /rdx :leaqMemIndexScaleDisp8Reg 64 | /rdx /rdi :movqMemReg 65 | 3 /rdi :shlqImm8Reg 66 | 8 /rdx /rsi :leaqMemDisp8Reg 67 | /rsi :pushqReg 68 | ::internalAllocateArray /rax :movqImmReg 69 | /rax :callqReg 70 | 71 | /rsi :popqReg 72 | /rax :pushqReg 73 | 74 | 8 /rax /rdi :leaqMemDisp8Reg 75 | /rax /ecx :movlMemReg 76 | 8 /rcx :subqImm8Reg 77 | :reprcx :movsb 78 | 79 | /rbx :pushqReg 80 | :retn 81 | ]] /eyoutputs defv 82 | 83 | # return the type of an object 84 | # 0 -> the object to analyze 85 | # 0 <- an integer from 86 | # 0 - 15 for normal heap objects (as per doc/notes object header) 87 | # 16 for array begin marker 88 | # 17 for quote begin marker 89 | # 18 for bottom of stack marker 90 | # 19 for error data marker 91 | # -1 for unknown object 92 | [[ 93 | /rbx :popqReg 94 | 95 | /rdx :popqReg 96 | 63 /rdx :btrqImm8Reg 97 | /integerType :jcLbl32 98 | 99 | /rdx /rax :movqRegReg 100 | 44 /rax :shrqImm8Reg 101 | 6 /rax :cmpqImm8Reg 102 | /markers :jnzLbl8 103 | 104 | 7 /rdx /rdx :movzxMem8Disp8Reg64 105 | 4 /rdx :shrqImm8Reg 106 | /done :jmpLbl8 107 | 108 | @markers 109 | 1 /rdx :cmpqImm8Reg 110 | /arrayMarker :jzLbl8 111 | 2 /rdx :cmpqImm8Reg 112 | /quoteMarker :jzLbl8 113 | %5555555555555555 /rax :movqImmReg 114 | /rax /rdx :cmpqRegReg 115 | /bottomMarker :jzLbl8 116 | emptyArray /rax :movqImmReg 117 | /rax /rdx :cmpqRegReg 118 | /emptyArrayConst :jzLbl8 119 | 120 | 4 /rdx :cmpqImm8Reg 121 | /errorMarker :jzLbl8 122 | /unknown :jmpLbl8 123 | 124 | @errorMarker 125 | 19 /rdx :movqImmReg 126 | /done :jmpLbl8 127 | 128 | @bottomMarker 129 | 18 /rdx :movqImmReg 130 | /done :jmpLbl8 131 | 132 | @quoteMarker 133 | 17 /rdx :movqImmReg 134 | /done :jmpLbl8 135 | 136 | @arrayMarker 137 | 16 /rdx :movqImmReg 138 | /done :jmpLbl8 139 | 140 | @emptyArrayConst 141 | 7 /rdx :movqImmReg 142 | /done :jmpLbl8 143 | 144 | @integerType 145 | /rdx /rdx :xorqRegReg 146 | 147 | @done 148 | 63 /rdx :btsqImm8Reg 149 | /rdx :pushqReg 150 | 151 | /rbx :pushqReg 152 | :retn 153 | 154 | @unknown 155 | ::internalAllocateInteger /rax :movqImmReg 156 | /rax :callqReg 157 | /rdx /rdx :xorqRegReg 158 | 1 /rdx :subqImm8Reg 159 | /rdx 8 /rax :movqRegMemDisp8 160 | /rax :pushqReg 161 | 162 | /rbx :pushqReg 163 | :retn 164 | ]] /eytype defv 165 | > _ ==globalFunctions { defv }' ::allocateOffsetStruct 166 | 167 | "typed" enterSubScope 168 | 169 | [ 170 | globalFunctions keys eydeff { | }' createScopeEntries 171 | createScopeExtensionEntries 172 | ] :execute 173 | 174 | leaveSubScope 175 | > -- 176 | 177 | # vim: syn=elymas 178 | -------------------------------------------------------------------------------- /compiler/elymasLexer.ey: -------------------------------------------------------------------------------- 1 | < 2 | { assembler -01 . } ":" deff 3 | { assemblerLibrary -01 . } "::" deff 4 | assembler .|label "@" deff 5 | "%" _ : -01 deff 6 | 7 | < 8 | [ /0 /1 /2 /3 /4 /5 /6 /7 /8 /9 ] ==digits 9 | 10 | { 0 ==result 11 | { "(.)(.*)" regex } { 12 | { eq }_ digits -01 index result 10 mul add =result 13 | } loop 14 | result 15 | } 16 | > -- /base10decode deff 17 | 18 | { .value base10decode ==v 19 | v 4294967296 lt { 20 | [ 21 | # load value 22 | v /rdx :movqImmReg 23 | 63 /rdx :btsqImm8Reg 24 | /rdx :pushqReg 25 | ] :execute 26 | } { 27 | [ 28 | # allocate int 29 | ::internalAllocateInteger /rax :movqImmReg 30 | /rax :callqReg 31 | 32 | # push int address on program stack 33 | /rax :pushqReg 34 | 35 | # type zero does not need to be changed 36 | 37 | # load value 38 | 8 /rax :addqImm8Reg 39 | v /rdx :movqImmReg 40 | /rdx /rax :movqRegMem 41 | ] :execute 42 | } ? * 43 | } /TOKINT 44 | 45 | { .value ::constStringCode :execute } /TOKSTR 46 | 47 | { .value ::constStringCode 48 | [ 49 | global .internalExecuteIdentifier /rax :movqImmReg 50 | /rax :callqReg 51 | ] cat :execute 52 | } /TOKID 53 | 54 | { "floats not supported during initial compilation stage" die } /TOKFLOAT 55 | > -- 4 |defv rep 56 | 57 | { /input defv 58 | "" { 59 | 4096 input .read cat 60 | _ "" eq not 61 | } { 62 | { _ "([^\\n]*)\\n(.*)" regex } { -102 -- TOKFLOAT TOKINT TOKSTR TOKID elymas .tokenize { 63 | _ .handle 64 | # assemblerLibrary .stackDump 65 | # assemblerLibrary .globalScopeDump 66 | } each } loop 67 | } loop -- 68 | } /executeFile deff 69 | 70 | # vim: syn=elymas 71 | -------------------------------------------------------------------------------- /compiler/elymasTokenize.ey: -------------------------------------------------------------------------------- 1 | < 2 | { ==f =*re _ ==s re f { s } ? * } /rxparse deffd 3 | 4 | { ==TOKID ==TOKSTR ==TOKINT ==TOKFLOAT 5 | " " cat 6 | { < /handle deff /value defv > } /token deff 7 | [ -01 { _ "" eq not } { 8 | 0 ==matched { =*f matched { -- } { { 1 =matched f } rxparse } ? * } /parse deffst 9 | 10 | { "^ +(.*)" regex } { } parse 11 | { "^#" regex } { "" } parse 12 | { "^(\\d+) +(.*)" regex } { TOKINT token -01 } parse 13 | { "^(\\d[0-9.]*([eE]-?\\d+)?) +(.*)" regex } { TOKFLOAT token -02 } parse 14 | { "^\"(.*)" regex } { 15 | "" /str defv 16 | { _ "^\"(.*)" regex { -01 -- 0 } { 1 } ? * } { 17 | 0 /strmatched defv { /f deff strmatched { -- } { { 1 =strmatched f } rxparse } ? * } /strparse deff 18 | 19 | { "^\\\\\\\\(.*)" regex } { str "\\" cat =str } strparse 20 | { "^\\\\e(.*)" regex } { str "\e" cat =str } strparse 21 | { "^\\\\n(.*)" regex } { str "\n" cat =str } strparse 22 | { "^\\\\r(.*)" regex } { str "\r" cat =str } strparse 23 | { "^\\\\0(.*)" regex } { str "\0" cat =str } strparse 24 | { "^\\\\\"(.*)" regex } { str "\"" cat =str } strparse 25 | { "^([^\"\\\\])(.*)" regex } { str -01 cat =str } strparse 26 | strmatched not { "Tokenization of string-like failed" die } rep 27 | } loop 28 | str TOKSTR token -01 29 | } parse 30 | { "^([^a-zA-Z0-9 ]+)([a-zA-Z0-9][^ ]*) +(.*)" regex } { -201 TOKSTR token " " -1203 cat cat } parse 31 | { "^([a-zA-Z0-9]+|[^a-zA-Z0-9 ]+) +(.*)" regex } { TOKID token -01 } parse 32 | 33 | matched not { "Tokenization failed: " -01 cat die } rep 34 | } loop -- ] 35 | } /tokenize deff 36 | > /elymas defv 37 | 38 | # vim: syn=elymas 39 | -------------------------------------------------------------------------------- /compiler/standard.ey: -------------------------------------------------------------------------------- 1 | |defv "==?" deffd 2 | |deff "=*?" deffd 3 | |defvst "==" deffd 4 | |deffst "=*" deffd 5 | |defvc "==:" deffd 6 | |deffc "=*:" deffd 7 | 8 | "}" | { 9 | { =*f ==x 10 | { x f } 11 | } quoted { } { * } ? * 12 | } ; "}_" defq 13 | 14 | { { -01 < ==o { o -01 }' "." | ; > -12 } } { 15 | quoted { }" { * }" ? * 16 | quoted { |deffst } { deffst }" ? * 17 | }" ; /via defq 18 | 19 | { -1110 ; ==f =*a len _ 20 | { 21 | 0 a 22 | 1 -102 range f each 23 | }' { "fold on empty array" die }' 24 | ? * 25 | } /fold deffd 26 | 27 | { _ =*a len 28 | [ 1 -1202 1 add range { -110 sub a -01 }' each -- ] # TODO: rethink this one, seems overly complicated 29 | } /reverse deffd 30 | 31 | { _ len { |or fold }' { -- 0 }' ? * }' /any deffd 32 | { _ len { |and fold }' { -- 1 }' ? * }' /all deffd 33 | 34 | { =*?p { 35 | [ -01 { _ p { } { -- } ? * } each ] 36 | } } /engrep deffd 37 | 38 | { engrep * } /grep deffd 39 | { -110 ; engrep |dom -20*1* } /indices deffd 40 | 41 | { =*p _ =*a len ==l 42 | 1 neg ==r 43 | 44 | 0 { 45 | _ l lt 1 neg r eq and 46 | } { 47 | _ a p { _ =r } { } ? * 48 | 1 add 49 | } loop -- 50 | r 51 | } /index deffd 52 | 53 | { 54 | not { "Assertion failure" die } rep 55 | } /assert deffd 56 | 57 | { ==s 58 | [ s keys { s -01 . }' each ] 59 | } /values deffd 60 | 61 | { _ =*conds len ==max 62 | 0 ==i { i max lt }" { 63 | i conds * { i 1 add conds * max =i }" { }" ? * 64 | i 2 add =i 65 | }" loop 66 | } /conds deffd 67 | 68 | { -1010 gt -021 ? }' /max deffd 69 | { -1010 lt -021 ? }' /min deffd 70 | 71 | # vim: syn=elymas 72 | -------------------------------------------------------------------------------- /doc/container.md: -------------------------------------------------------------------------------- 1 | Container Types 2 | =============== 3 | 4 | Apart from arrays and scopes, a few other container types are provided in the standard library. 5 | 6 | Lists 7 | ----- 8 | 9 | A list maps integers to arbitrary objects. Access to members takes time linear in the index. 10 | 11 | A new list can be created with `list` and appended to with `append` or `append1` (the latter 12 | will not distribute over domain having inputs). 13 | 14 | list ==l 15 | /a l .append 16 | /b l .append 17 | /c l .append 18 | l dump 19 | 20 | l |dump each 21 | "a" 22 | "b" 23 | "c" 24 | l len dump 25 | 0000000000000003 26 | list ==m 27 | [ /a /b /c ] m .append1 28 | m len dump 29 | 0000000000000001 30 | 31 | Lists can be used similar to functions from integers or arrays. Just as with 32 | arrays, negative indices start from the end of the list towards the beginning. 33 | Write access is provided via `=[]` as usual. 34 | 35 | list ==l 36 | [ /a /b /c ] l .append 37 | 0 l * dump 38 | "a" 39 | 1 neg l * dump 40 | "c" 41 | l dom dump 42 | [ 43 | 0000000000000000 44 | 0000000000000001 45 | 0000000000000002 46 | ] 47 | /foo 1 l =[] 48 | l |dump each 49 | "a" 50 | "foo" 51 | "c" 52 | l l { cat } '*0.0 |dump each 53 | "aa" 54 | "bb" 55 | "cc" 56 | 57 | List can be used like a stack via `pop`. 58 | 59 | list ==l 60 | [ /a /b /c ] l .append 61 | l .pop 62 | l |dump each 63 | "a" 64 | "b" 65 | 66 | Maps 67 | ---- 68 | 69 | Maps wrap scopes to provide an array-like container mapping from strings to arbitrary objects. 70 | 71 | A new map can be created with `map`, new members are added via `=[]` when the key does not exist 72 | beforehand. Access to specific members works like in arrays via `*`. Testing for members can be 73 | done via `has`. 74 | 75 | map ==m 76 | 1 /foo m =[] 77 | 2 /bar m =[] 78 | m dump 79 | 80 | m dom dump 81 | [ 82 | "foo" 83 | "bar" 84 | ] 85 | m |dump each 86 | 0000000000000001 87 | 0000000000000002 88 | /foo m * dump 89 | 0000000000000001 90 | /foo m .has dump 91 | 0000000000000001 92 | /FOO m .has dump 93 | 0000000000000000 94 | m 2 mul ==m2 95 | m2 dom dump 96 | [ 97 | "foo" 98 | "bar" 99 | ] 100 | m2 |dump each 101 | 0000000000000002 102 | 0000000000000004 103 | /foo m2 * dump 104 | 0000000000000002 105 | 106 | Trees 107 | ----- 108 | 109 | Trees provide mapping from keys to arbitrary objects, 110 | keeping the keys in `lt`/`eq`/`gt` ascending order. Otherwise they should work just as maps. 111 | 112 | tree ==t 113 | 1 /foo t =[] 114 | 2 /bar t =[] 115 | t dump 116 | 117 | t dom dump 118 | [ 119 | "bar" 120 | "foo" 121 | ] 122 | t |dump each 123 | 0000000000000002 124 | 0000000000000001 125 | /foo t * dump 126 | 0000000000000001 127 | /foo t .has dump 128 | 0000000000000001 129 | /FOO t .has dump 130 | 0000000000000000 131 | t 2 mul ==t2 132 | t2 dom dump 133 | [ 134 | "bar" 135 | "foo" 136 | ] 137 | t2 |dump each 138 | 0000000000000004 139 | 0000000000000002 140 | /foo t2 * dump 141 | 0000000000000002 142 | -------------------------------------------------------------------------------- /doc/conventions.md: -------------------------------------------------------------------------------- 1 | Conventions 2 | =========== 3 | 4 | Global function names try to follow a certain schema. The initial character (and sometimes later ones as well) 5 | roughly connect to various topics as follows: 6 | 7 | * `!`: Co-routines 8 | * `"`: Strings 9 | * `#`: Scope based complex data types; comments 10 | * `$`: - 11 | * `%`: - 12 | * `&`: - 13 | * `'`: Types 14 | * `(`: - 15 | * `)`: - 16 | * `*`: Function execution 17 | * `+`: - 18 | * `,`: Position markers 19 | * `-`: Stack manipulation 20 | * `.`: Field dereference 21 | * `/`: Keyword-like strings 22 | * `:`: - 23 | * `;`: Function composition 24 | * `<`: Scope start 25 | * `=`: Assignment 26 | * `>`: Scope end 27 | * `?`: Ternary operator; error handling 28 | * `@`: - 29 | * `[`: Array begin 30 | * `\`: Executing dereference 31 | * `]`: Array end 32 | * `^`: - 33 | * `_`: Stack manipulation 34 | * `` ` ``: - 35 | * `{`: Code begin 36 | * `|`: Nonexecuting dereference 37 | * `}`: Code end 38 | * `~`: - 39 | -------------------------------------------------------------------------------- /doc/coroutines.md: -------------------------------------------------------------------------------- 1 | Coroutines 2 | ========== 3 | 4 | The current (userspace) program state of an elymas program consists of the 5 | heap, the data stack, the call stack and the current instruction pointer. The 6 | data stack is *the* stack, programs are manipulating all the time, whereas the 7 | *call* stack holds information about what functions to return to after the 8 | current one finishes and what the current local scope is. 9 | 10 | The coroutine functions offer ways to create and switch to new program states 11 | called *coroutines* which have separate call and possibly data stacks. 12 | 13 | `!!` 14 | ---- 15 | 16 | This takes a function objects from the stack and initializes a new coroutine 17 | with an empty call and data stack. This new coroutine is returned. 18 | 19 | { "Hello World" dump * } !! ==coroutine 20 | coroutine * 21 | "Hello World" 22 | 23 | 24 | Calling Coroutines 25 | ------------------ 26 | 27 | Coroutines can be called either with `*`, in which only the call stack is switched, but 28 | the same data stack is used as before the call. However, before the coroutine continues 29 | execution, the coroutine from which the call originated is pushed to the data stack, so 30 | the called coroutine can return to it (instead of running into an empty call stack at 31 | the end of the execution). 32 | 33 | Observe how execution switches between the coroutine and the implicit initial coroutine: 34 | 35 | { "Hello" dump * "World" dump * } !! ==coroutine 36 | coroutine * " " dump * 37 | "Hello" 38 | " " 39 | "World" 40 | 41 | Alternatively, `!` can be used to call a coroutine and explicitely move items to the 42 | target coroutine's data stack. 43 | 44 | { ==ret "42" -01 { 1 } { "Holding:" dump -101 dump "Received:" dump dump ret 0 ! =ret } loop } !! ==coroutine 45 | "23" 46 | /foo coroutine 1 ! -- 47 | "Holding:" 48 | "42" 49 | "Received:" 50 | "foo" 51 | /bar coroutine 1 ! -- 52 | "Holding:" 53 | "42" 54 | "Received:" 55 | "bar" 56 | "On main stack:" dump dump 57 | "On main stack:" 58 | "23" 59 | 60 | 61 | `!!'` 62 | ----- 63 | 64 | The purpose of this function is to create coroutine with a cloned call stack. The created 65 | coroutine will return to the call site of `!!'` after execution. However, the original 66 | call will also return after `!!'` as usual, so to disambiguate the two more easily, 67 | `!!'` takes two function objects. The topmost one *c* becomes the coroutine and pushed 68 | to the data stack, the second argument then gets called in the usual fashion, thereby 69 | receiving the coroutine version of *c* on the data stack. 70 | 71 | Note how the greeting gets dumped twice as the coroutine continues execution after 72 | `!!'`: 73 | 74 | { 75 | { } =*coroutine 76 | { =coroutine } { "coroutine" dump } !!' 77 | "Hello World" dump 78 | coroutine 79 | } * 80 | "Hello World" 81 | "coroutine" 82 | "Hello World" 83 | 84 | 85 | Uses of Coroutines 86 | ------------------ 87 | 88 | One typical use of coroutines is separation between value generation and processing: 89 | 90 | { ==r 91 | 1 1 { 1 } { _ r 1 ! =r -010 add } loop 92 | } !! { 0 ! -- }_ =*fib 93 | fib dump 94 | 0000000000000001 95 | fib dump 96 | 0000000000000002 97 | fib dump 98 | 0000000000000003 99 | fib dump 100 | 0000000000000005 101 | fib dump 102 | 0000000000000008 103 | 104 | While this seem a bit pointless in the example above, instead of calculating the fibonnacci 105 | sequence, the coroutine might be tasked with more complex sequences, in particular ones where 106 | local state is more complex than just two integers. 107 | 108 | Another use case of coroutines is creating checkpoints in the code where execution can 109 | restart if something goes wrong - or just because you love gotoesque execution flow: 110 | 111 | { 112 | { 113 | { } { -- restart } !!' 114 | } /restart deffd 115 | 116 | 0 ==i 117 | 118 | restart ==checkpoint 119 | 120 | i 1 add =i 121 | i dump 122 | 123 | i 7 lt { checkpoint 0 ! } rep 124 | } * 125 | 0000000000000001 126 | 0000000000000002 127 | 0000000000000003 128 | 0000000000000004 129 | 0000000000000005 130 | 0000000000000006 131 | 0000000000000007 132 | 133 | A third use would be thread-like processing of network requests, in particular if network 134 | sessions are stateful in a complex way. 135 | -------------------------------------------------------------------------------- /doc/err.md: -------------------------------------------------------------------------------- 1 | Error handling 2 | ============== 3 | 4 | The easiest way to deal with errors in elymas is the `die` function. It takes a string, dumps it to the 5 | error output and terminates the program. It might however be preferable to act more gracefully if problems 6 | are encountered. To this end, an error handling library was created. 7 | 8 | The main idea is to have the error locations suggest possible further actions from which the calling 9 | function can then select a suitable one depending on circumstances. To give an example: While it would be 10 | perfectly ok to terminate the program on a failed `sys .read` in a single-user command line application, 11 | the same can certainly not be said about a webserver. However the code of `sys .read` cannot possibly know 12 | how to react correctly. 13 | 14 | The error handling does not automatically rewind the stack like it is usual in many other languages. If such 15 | behaviour is desired, it can be emulated via coroutines. 16 | 17 | Usually, different kinds of errors need different handling. Hence most functions take a string describing the 18 | kind of error which occured. This string is always treated as a prefix of a possibly more detailed description. 19 | If an error of (hypthetical) kind "io.write.diskfull" is raised, a handling routine for "io.write" will catch it, 20 | as would a handler for "io". 21 | 22 | 23 | `??` 24 | ---- 25 | 26 | Takes a string and raises an error of the specified kind. 27 | 28 | ??fatal.testError 29 | 30 | `???` 31 | ----- 32 | 33 | Takes a string and a scope and raises an error of the kind specified by the string. The scope members 34 | are possible ways to react to the error provided to upper layers of the application. 35 | 36 | < 37 | { "ignored" dump } =*ignore 38 | { "oops" die } =*terminate 39 | > ???fatal.testError 40 | 41 | 42 | `?!` 43 | ---- 44 | 45 | Specifies behavior if an error occurs. Takes two function objects. The first is executed. If an error occurs 46 | during its execution, the second is invoked with the error handling scope provided on the stack. 47 | 48 | { 49 | < 50 | { "ignored" dump } =*ignore 51 | { "oops" die } =*terminate 52 | > ???fatal.testError 53 | } /maybeFailFunction deff 54 | |maybeFailFunction { .terminate } ?!fatal # handle all fatal.* errors by the .terminate action 55 | 56 | 57 | `??!` 58 | ----- 59 | 60 | Specifies behavior if an error occurs by mapping a lower level error to a higher level one. 61 | 62 | { ... } # do stuff to the database 63 | { ==lowLevelHandlers < # capture handling proposals from lower levels 64 | { ... } =*rollback # provide new suggestions how to handle the error ... 65 | { ... } =*closeDatabase # possibly using low-level suggestions while doing so 66 | { ... } =*terminate 67 | > ??!io.database } ?!io # map all io.* errors do io.database errors 68 | 69 | 70 | `??!'` 71 | ------ 72 | 73 | Just like `??!`, but does not take a string. Instead it re-raises the original error kind string. 74 | 75 | 76 | `?!!` 77 | ----- 78 | 79 | Applies an array of error handling strategies in turn. 80 | 81 | { ... } # do stuff to the database 82 | [ 83 | { .rollback } # try the .rollback handler suggested by lower level 84 | { .closeDatabase } # if it raises an error again, try the .closeDatabase handler 85 | { "cannot recover from error" die } # if this in turn fails, just die 86 | ] ?!!io.database # apply above rules to any io.database.* errors 87 | 88 | 89 | `!!?` 90 | ----- 91 | 92 | Clones the current coroutine state and returns it. This allows resetting the stack and 93 | instruction pointer to an earlier state. 94 | 95 | [ "config.xml" "config.xml.bak" "config.xml.orig" ] ==configFiles 96 | 0 ==currentConfig 97 | !!? ==checkpoint # clone current coroutine state 98 | { 99 | currentConfig configFiles * parse ... 100 | } { # on error: 101 | -- # ignore lower level suggestions 102 | currentConfig 1 add =currentConfig # try a different config file 103 | currentConfig configFiles len lt { 104 | checkpoint 0 ! # rewind execution back to checkpoint 105 | } rep # ... if candidates remain 106 | } ?!io # do this on any io.* errors 107 | -------------------------------------------------------------------------------- /doc/ffi.md: -------------------------------------------------------------------------------- 1 | Foreign Function Interface 2 | ========================== 3 | 4 | Elymas supports loading of shared object based libraries (`*.so`) utilizing the standard libc facilities. 5 | This support is only available in the `shared` interpreter, which different from all other interpreters, 6 | dynamically links against libc. 7 | 8 | sys .so ":" via 9 | "/lib/x86_64-linux-gnu/libm.so.6" :dlopen not { "Failed to load." die } rep 10 | "sin" "d" "d" :resolveFunction =*sin 11 | 0 31 range { 10.0 div sin dump } each 12 | 13 | 14 | `sys .so .dlopen` 15 | ----------------- 16 | 17 | Takes a filename of a shared object from the stack and loads that shared object. A handle is returned 18 | but can savely be ignored except to test it against zero, which would signify an error. 19 | 20 | `sys .so .resolveFunction` 21 | -------------------------- 22 | 23 | Takes a function name, a string describing function arguments and a string describing the return type 24 | from the stack. It resolves the name within all currently loaded objects, and returns an elymas function 25 | object which wraps the underlying foreign function. 26 | 27 | The input specification string consists of single characters, each describing the type of one input 28 | argument. 29 | 30 | * `p` - A pointer argument. 31 | * `i` - An integer (of any width). 32 | * `f` - A float. 33 | * `d` - A double. 34 | * `s` - A string. A pointer to a zero-terminated string is passed to the C-function. 35 | * `b` - A buffer. A pointer the beginning of the string contents is passed to the C-function. 36 | 37 | When specifying the return type of the function, integer widths matter, hence the following 38 | options are available. 39 | 40 | * `v` - No return value 41 | * `p` - Pointer return value 42 | * `u8` - `uint8_t` return value 43 | * `u16` - `uint16_t` return value 44 | * `u32` - `uint32_t` return value 45 | * `u64` - `uint64_t` return value 46 | * `i8` - `int8_t` return value 47 | * `i16` - `int16_t` return value 48 | * `i32` - `int32_t` return value 49 | * `i64` - `int64_t` return value 50 | * `s` - String return value (will be copied) 51 | * `f` - float return value 52 | * `d` - double return value 53 | 54 | 55 | `sys .so .rawContentAddress` 56 | ---------------------------- 57 | 58 | Returns the address of the first byte of a string. This can be handy to build complex C structures 59 | within a string memory and then passing the pointer to a foreign function. 60 | 61 | `sys .so .peekString` 62 | --------------------- 63 | 64 | Takes an address and scans that address for a C-style zero-terminated string 65 | (of some implementation defined maximum length). This string is subsequently returned. 66 | 67 | `sys .so .freeze` 68 | ----------------- 69 | 70 | A binary created by `sys .freeze` will have no dynamic dependencies, hence libc is not available. If you 71 | want to use dynamic libraries in your binary, use `sys .so .freeze` which will create an ELF binary which 72 | is dynamically linked against libc. The loaded libc is then used to call `dlopen` and `dlsym` to load 73 | further libraries. The `shared` interpreter has been created with `sys .so .freeze`. 74 | 75 | 76 | Libraries interfaced so far 77 | --------------------------- 78 | 79 | * `ffi .pq` - PostgreSQL 80 | -------------------------------------------------------------------------------- /doc/parsing.md: -------------------------------------------------------------------------------- 1 | Parsing 2 | ======= 3 | 4 | Elymas has a very simplistic parser (if at all). Parsing works as follows: 5 | * Spaces separate things. 6 | * If a `#` is encountered, ignore rest of line. This implements comments. 7 | * If a sequence of digits is encountered, this is an integer literal and gets 8 | pushed to the stack. 9 | * If something looks like a float, i.e. matches (\\d[0-9.]*([eE]-?\\d+)?), 10 | this is a float literal and gets pushed to the stack. 11 | * If a `"` is encountered, a string literal begins. Within a string, backslash 12 | escapes special characters. `\\` becomes single backslash, `\n` is a new line, 13 | `\r` is a carriage return, `\0` is the NUL character (all bits zero). All 14 | other (non-escaped) characters just become part of the string. 15 | * If a sequence of alphanumeric characters (a-zA-Z0-9) is encountered, 16 | it is looked up in the current scope. This is how normal functios like `dump` 17 | get referenced. 18 | * If a sequence of non-alphanumeric characters is encountered, 19 | it is looked up in the current scope. This is how functions like `_` work. 20 | * If a sequence starts with non-alphanumeric characters, but then an alphanumeric 21 | character is encountered, this latter part is converted to a string literal 22 | (backslash escapes do not apply) and pushed to the stack. Afterwards the 23 | non-alphanumeric prefix is looked up in the current scope. This is how 24 | `/abc` becomes `"abc"`: The string is created during parsing and afterwards 25 | the identity function is applied. 26 | 27 | Additionally, the parser has a quote-level counter which is increased by `{` 28 | and decreased by `}`. If the quote-level is non-zero, i.e. the parser is in 29 | quote mode, the resolution of names is postponed and a function object doing 30 | the resolution is pushed instead. 31 | -------------------------------------------------------------------------------- /doc/scopes.md: -------------------------------------------------------------------------------- 1 | Scopes 2 | ====== 3 | 4 | A scope maps (variable) names to values. Each such binding also specifies how and when the referenced 5 | object gets executed and what assumptions the optimizer may make about later values of the same name. 6 | To create a mapping from a name to a value, various functions starting with `def` exist. Some of them 7 | are aliased to `==` and similar functions. 8 | 9 | They allow specifying four different execution modes: 10 | * _v_alue: Upon dereference, the object is placed on top of the stack. 11 | * _f_unction: Upon dereference, the object is executed (equivalently the object is placed on top of the stack, then `*` is executed). 12 | * _m_ember: Upon dereference, the containing scope is pushed on the stack, then the object is executed. 13 | * _q_uoting: The object is executed as soon as the name is encountered in the input stream, even if the parser is currently in quote 14 | mode. 15 | 16 | They also allow specifying four different optimization guarantees: 17 | * _s_tatic: The name always resides at the same scope slot. Scope slots are assigned deterministically. If the same set of variables 18 | is always declared in scopes encountered by a certain piece of code, then this piece of code can savely assume static 19 | names. This also guarantees that the execution mode of this name is always the same. 20 | * _t_ype constant: The name always refers to the same type of object. If the variable held an integer once, it is required 21 | to always hold an integer and so on. Arrays and functions are only type constant if they keep the same 22 | function signature (i.e. same nesting depth in case of arrays). 23 | * _c_onstant: The referenced object stays identical forever. This implies static and type constant. 24 | * _d_eep constant: The referenced object and all objects reached through it (i.e. submembers in case of a scope) stay identical forever. 25 | This implies constant. 26 | 27 | No optimization guarantees can be specified for quoting execution mode, as optimization is not applied in this parsing stage. To allow `defq` from within nested scopes, `defq` itself has quoting execution mode. 28 | 29 | The resulting function names are the concatenation of `def`, the desired execution mode character (`v`, `f`, `m`, `q`) and the 30 | desired optimization guarantee (none, `s`, `t`, `st`, `c`, `d`). 31 | 32 | This scheme results in 19 different functions. All of these functions take from the stack a name (on top of stack) and a value 33 | to associate with the name. 34 | 35 | 5 /five defv 36 | { "hi" dump } /greet deffst 37 | 42 "ANSWER" defvd 38 | 39 | Some of these functions are aliased, because they appear particularly useful: 40 | 41 | * `==?` aliases `defv`, i.e. value definition without optimization guarantees 42 | * `==` aliases `defvst`, i.e. value definition with static and type constness 43 | * `==:` aliases `defvc`, i.e. value definition with constness 44 | * `=*?` aliases `deff`, i.e. executable definition without optimization guarantees 45 | * `=*` aliases `deffst`, i.e. executable definition with static and type constness 46 | * `=*:` aliases `deffc`, i.e. executable definition with constness 47 | 48 | The value associated with a name can be updated using the `=` function. It takes a name to update and the new value from the stack. 49 | 50 | 0 ==i 51 | i 1 add =i 52 | i dump 53 | 0000000000000001 54 | 55 | 56 | Scope objects on the stack 57 | -------------------------- 58 | 59 | There is always a current scope. This is the scope where lookup happens during code parsing and this is where the `def` function 60 | family puts values. The current scope object can also be put on the stack using the `scope` function. All scope objects but the 61 | global one have a single parent scope where lookup continues if a name can not be resolved in the scope itself. 62 | 63 | The current scope can also be switched using `<` and `>`. `<` takes the current scope as the parent of a new scope which then 64 | becomes current. `>` pushes the current scope to the stack and makes its parent the new current scope. This allows construction 65 | of structured datatypes. To this end, the `.` function takes a name and a scope object from the stack and resolves the name in 66 | the given scope object. 67 | 68 | < 69 | 1 ==one 70 | > _ dump 71 | 72 | .one dump 73 | 0000000000000001 74 | 75 | Function objects created by a `{`, `}` pair remember the scope they have been created in. Upon execution, they create a new 76 | scope object which has this remembered scope as its parent. In effect, this results in closure semantics for function objects. 77 | 78 | < 79 | 0 ==i 80 | { i dump i 1 add =i } 81 | > -- /dumpAndIncrement deffst 82 | dumpAndIncrement 83 | 0000000000000000 84 | dumpAndIncrement 85 | 0000000000000001 86 | dumpAndIncrement 87 | 0000000000000002 88 | 89 | Sometimes it's useful to assign a different parent pointer than the current scope to a new scope object. This can be 90 | achieved by the `>'` function. It behaves like `>` but takes the parent pointer of the new object from the stack. 91 | 92 | < 93 | 0 ==i 94 | > ==parent 95 | < 96 | { i dump i 1 add =i } 97 | parent 98 | >' -- /dumpAndIncrement deffst 99 | dumpAndIncrement 100 | 0000000000000000 101 | dumpAndIncrement 102 | 0000000000000001 103 | dumpAndIncrement 104 | 0000000000000002 105 | 106 | As `>'` only assigns the parent pointer when the scope stops being the current scope, before its execution the parent 107 | was set as usual, i.e. the current scope before `<`. This allows for interesting possibilities. Note that names in 108 | quoted mode are only resolved during first execution. 109 | 110 | 111 | Missing members 112 | --------------- 113 | 114 | If a scope member is accessed, which is not available, the program will call `die` and be dead. Unless, that is, 115 | that the scope happens to have `#.`, `#.|`, or `#.=` defined, which are used to dynamically handle missing members 116 | on `.` (or quoted identifiers), on `|` and on `=` respectively. To fully fake missing members, there also exists the 117 | possibility to declare `#.?` which will be invoked by `.?` when the member does not exist. 118 | 119 | < 120 | { ==memberName "#. called with: " memberName cat dump } "#." deffd 121 | { ==memberName "#.| called with: " memberName cat dump } "#.|" deffd 122 | { ==memberName "#.? called with: " memberName cat dump } "#.?" deffd 123 | { ==memberName ==value "#.= called with: " memberName cat dump value dump } "#.=" deffd 124 | > ==s 125 | s .hello_world 126 | "#. called with: hello_world" 127 | < { "value" =random_name } s >' -- * 128 | "#.= called with: random_name" 129 | "value" 130 | -------------------------------------------------------------------------------- /doc/server.md: -------------------------------------------------------------------------------- 1 | Server Algorithms 2 | ================= 3 | 4 | As a convenience for coding TCP/IP network servers some algorithms 5 | are provided. 6 | 7 | All these server templates work by first creating an object, then 8 | configuring it via various setters, most importantly setting the 9 | event handler for new connections and finally starting the event 10 | loop. So far, all event loops are based on the epoll(7) facility. 11 | 12 | net .alg .epollServer 13 | --------------------- 14 | 15 | net .alg .epollServer "+" via 16 | { 8000 } +port 17 | { ":" via 18 | # : provides methods to communicate with the new connection 19 | # :read, :write, :close, :ctl (as in EPOLL_CTL) 20 | 21 | "Welcome to server\n" :write 22 | 23 | < 24 | { 4096 :read _ dump "" eq { :close } rep } =*in 25 | { "Did't :ctl for outgoing data" die } =*out 26 | { "Error" die } =*err 27 | > 28 | } +accept 29 | +run 30 | 31 | `net .alg .epollServer` creates a new server, on which the following options 32 | can be set, and `accept` and `port` must be set before starting the server. 33 | 34 | `port`: Takes a function which returns the port number to bind. 35 | 36 | `accept`: Takes a function which takes a scope containing capabilities 37 | to communicate over the newly accepted connection and returns a scope 38 | which provides functions to call on `in`coming data, `out`going kernel 39 | buffer space and `err`ors in the connection. 40 | 41 | The capabilities of the connection are `read` which takes the maximal number of 42 | bytes to read and returns a string of the actually read bytes or the empty string 43 | if the connection ended. The member `write` takes a string and writes it to the 44 | connection - returning the number of bytes written. `close` immediately closes 45 | the connection and `ctl` takes a new set of flags `bor`'ed together from 46 | `sys .linux .epoll .EPOLLIN`, `.EPOLLOUT`, and `.EPOLLERR`. 47 | 48 | `interval`: Takes a function which provides the number of microseconds to sleep 49 | during the next epoll_wait(2) syscall. 50 | 51 | net .alg .epollServer "+" via { 1000 } +interval 52 | # server will abort epoll_wait after 1ms 53 | 54 | `reuseAddr`: Takes a function which takes a socket file descriptor and performs 55 | whatever shenanigans it deems appropriate before the socket is passed to bind(2). 56 | The default for this option applies SO_REUSEADDR, hence the separate option, if you 57 | whish to disable it set `reuseAddr` to `{ -- }`, i.e. just discard the socket descriptor. 58 | 59 | net .alg .epollServer "+" via { -- } +reuseAddr 60 | # server will not set SO_REUSEADDR 61 | 62 | FIXME: There should be a general option setting option as well (and only the default-active 63 | ones should be available for disabling) 64 | 65 | 66 | net .alg .bufferedEpollServer (what you actually want to use) 67 | ------------------------------------------------------------- 68 | 69 | Just as `net .alg .epollServer` and actually based on it, but provides buffering for all 70 | in- and output so you don't have to track the number of bytes read and written and can 71 | instead handle stuff on a higher level. To this end, `accept` works slightly different. 72 | 73 | The capabilities `write`, `read`, `close` are provided as in `net .alg .epollServer`, 74 | where `close` still immediately closes the connection, whereas the new capability 75 | `finish` will first write the remaining output buffer bytes before actually closing 76 | the connection. 77 | 78 | The members of the `accept` returned scope are `in`, `err`, and `end`. The `in` 79 | handler gets the current input buffer and is expected to return whatever can not 80 | yet be handled (i.e. pars whatever prefix you like and return the rest), `err` is 81 | called when an error occurs on the connection and `end` is called when the remote 82 | end closes the connection. 83 | 84 | net .alg .bufferedEpollServer "+" via 85 | { 8000 } +port 86 | { ":" via 87 | # available methods are :read, :write, :close, :finish 88 | 89 | "Welcome to server\n" :write 90 | 91 | < 92 | { ==s 93 | { s len 4 ge } { "4 chars by you: " 4 s str .prefix cat "\n" cat :write 4 s str .postfix =s } loop 94 | s 95 | } =*in 96 | { "Bye..." :write :finish } =*end 97 | { "Error" die } =*err 98 | > 99 | } +accept 100 | +run 101 | 102 | FIXME: Fix the bug which produces two "Bye..." messages. 103 | 104 | `net .alg .bufferedEpollServer` takes the same options as `net .alg .epollServer` 105 | and additionally provides `outputBufferLimit` which takes a function which 106 | returns the maximum number of output buffer bytes you are willing to keep 107 | around for slow reading clients. 108 | 109 | net .alg .bufferedEpollServer "+" via { 16 } +outputBufferLimit 110 | # server will raise an error if output buffer grows above 16 bytes 111 | 112 | 113 | net .alg .httpServer 114 | -------------------- 115 | 116 | This is not yet a full featured HTTP server, but works a little bit. 117 | It is based on `net .alg .bufferedEpollServer` and takes all options of the former. 118 | Additionally `inputBufferLimit` also exists, which puts a limit on the 119 | total request size (including request body). 120 | 121 | You are not supposed to provide an `accept`, but instead 122 | call `request` to provide a function which handles the requests. 123 | 124 | net .alg .httpServer "+" via 125 | { 8080 } +port 126 | { ":" via 127 | # available methods are :ok, :fail, :close, :write, :finish 128 | # additional members are :headers, :method, :url, :args 129 | :headers keys dump 130 | :method dump 131 | :url dump 132 | :args keys dump 133 | :body dump 134 | "O hi!" "text/html" :ok 135 | } +request 136 | +run 137 | -------------------------------------------------------------------------------- /doc/sys.md: -------------------------------------------------------------------------------- 1 | System Interaction 2 | ================== 3 | 4 | Some facilities have been developed to access the outside world. 5 | 6 | `sys .exit` 7 | ----------- 8 | 9 | Exists the program with the indicated error code. 10 | 11 | 0 sys .exit # successful termination 12 | 13 | 14 | `sys .file` 15 | ----------- 16 | 17 | Creates a scope representing a file. This object supports `.open`, `.close`, `.read`, `.write`, `.writeall`, `.eachLine`. 18 | Three files `sys .in`, `sys .out`, `sys .err` are predefined and represent the standard input, output and error streams respectively. 19 | 20 | sys .file ":" via 21 | "foo.txt" :open 22 | 8 :read dump # first 8 bytes of foo.txt, possibly less if foo.txt is shorter 23 | { dump } :eachLine # dump each line of foo.txt (excluding the 8 bytes already read) 24 | :close 25 | "Hallo Welt!\n" sys .out .writeall 26 | Hallo Welt! 27 | 28 | As `.write` directly maps to the write(2) syscall, it might not write all bytes. Instead it returns the number of bytes written as an integer. 29 | Usually, you want to use `.writeall` which will call write(2) repeatedly, until all bytes are written. 30 | 31 | `sys .fdToFile` will create a file representing scope directly from a unix file descriptor number. 32 | 33 | 34 | `sys .freeze` 35 | ------------- 36 | 37 | To create stand-alone executables, `sys .freeze` takes a filename and a function object and creates an executable which will 38 | execute the function object when started. 39 | 40 | { "Hello World!\n" sys .out .writeall 0 sys .exit } "hello" sys .freeze 41 | 42 | An elymas interpreter can be implemented via `include` easily: 43 | 44 | { 45 | sys .argv len { 0 sys .argv * } { "/proc/self/fd/0" } ? * include 46 | 0 sys .exit 47 | } "interpreter" sys .freeze 48 | 49 | 50 | `sys .mkdir` 51 | ------------ 52 | 53 | Creates a new directory. 54 | 55 | 56 | `sys .ls` / `sys .readdir` 57 | -------------------------- 58 | 59 | List the contents of a directory. `sys .ls` excludes files with a leading dot. 60 | 61 | 62 | `sys .rename` 63 | ------------- 64 | 65 | Takes two filenames. Renames the first (stack second-to-top) to the second (stack top). 66 | -------------------------------------------------------------------------------- /doc/tutorial.md: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | This tutorial attempts to give a rough overview over the everyday syntax of Elymas. 5 | It's main purpose is to make the rest of the documentation readable, in particular 6 | to enable the reader to understand the examples given therein. It is by no means 7 | a complete presentation of all features. 8 | 9 | 10 | Getting started 11 | --------------- 12 | 13 | First, you need an executable. 14 | 15 | git clone https://github.com/Drahflow/Elymas.git 16 | cd Elymas && make 17 | 18 | This should result in various executables. For the remainder of this tutorial, just use 19 | 20 | elymas/shared 21 | 22 | as it comes with all libraries preloaded. Start it and enter 23 | 24 | "Hello World!" dump 25 | 26 | this should yield the obvious result or a bug report to the author. 27 | If `elymas/shared` did not work for some reason or another, you can also use 28 | 29 | elymas/loaded 30 | 31 | which has no shared-library support, but should be good enough for most of the tutorial. 32 | 33 | 34 | Simple functions 35 | ---------------- 36 | 37 | Elymas is a stack based language. Instead of passing arguments to (and return values from) 38 | functions explicitely, there is a global stack of data items all functions work upon. 39 | 40 | One such function is `dump`. It takes the topmost value from the stack and outputs it to 41 | the standard error stream. 42 | 43 | 1 dump 44 | 0000000000000001 45 | 46 | Mathematical functions work similarly. They take arguments from the stack and leave the 47 | result on top of the stack (where it can be consumed by `dump`). 48 | 49 | 5 2 add dump 50 | 0000000000000007 51 | 5 2 sub dump 52 | 0000000000000003 53 | 5 2 mul dump 54 | 000000000000000A 55 | 5 2 div dump 56 | 0000000000000002 57 | 5 2 mod dump 58 | 0000000000000001 59 | 60 | 61 | Strings 62 | ------- 63 | 64 | There are two common ways to create a string on the stack. 65 | 66 | "This is a string" dump 67 | "This is a string" 68 | /thisToo dump 69 | "thisToo" 70 | 71 | Strings can contain some escapes using backslash. 72 | 73 | "Two\nlines" dump 74 | "Two 75 | lines" 76 | "\\" dump 77 | "\" 78 | 79 | 80 | Function objects 81 | ---------------- 82 | 83 | Multiple functions (and constants) can be combined into one function by enclosing them 84 | in braces. The resulting objects reside on the stack just like all other values. 85 | The function `*` executes such function objects. 86 | 87 | { 5 add } dump 88 | 89 | 3 { 5 add } * dump 90 | 0000000000000008 91 | 92 | 93 | Variables 94 | --------- 95 | 96 | Variables can be declared and at the same time assigned by `==`. 97 | 98 | 2 ==two 99 | two two add dump 100 | 0000000000000004 101 | { 2 add } ==addTwo 102 | 2 addTwo * dump 103 | 0000000000000004 104 | 105 | 106 | Scopes 107 | ------ 108 | 109 | Variables live in scopes which are hierarchically nested. Every scope has a parent scope, 110 | except the topmost (global) scope. If a variable is not found in a scope, its parent is 111 | queried for it. Every function object execution creates a fresh scope, in effect allowing 112 | local variables. 113 | 114 | 2 ==two 115 | { ==i two i add } ==addTwo 116 | 2 addTwo * dump 117 | 0000000000000004 118 | 3 addTwo * dump 119 | 0000000000000005 120 | 121 | Scopes can also be created explicitely using `<` and `>`. Variables in such an explicit 122 | scope are accessed through `.`. 123 | 124 | < 2 ==two > dump 125 | 126 | < 2 ==two > .two dump 127 | 0000000000000002 128 | 129 | 130 | Stack manipulation 131 | ------------------ 132 | 133 | It is often helpful to rearrange values on the stack, for example because a function 134 | expects arguments in a different order. The function `-` does this. 135 | 136 | /a /b /c dump dump dump 137 | "c" 138 | "b" 139 | "a" 140 | /a /b /c -0012 dump dump dump dump 141 | "a" 142 | "b" 143 | "c" 144 | "c" 145 | 146 | The digits after the `-` refer elements of the stack, `0` denotes the topmost element, 147 | `1` the next one and so on until `9`. The function `_` finally is identical to `-00`, 148 | i.e. it duplicates the topmost element. It exists separately, because this use is so 149 | common. 150 | 151 | /a _ dump dump 152 | "a" 153 | "a" 154 | 155 | To drop the topmost stack element, use `--`. 156 | 157 | /a /b -- dump 158 | "a" 159 | 160 | 161 | Other useful functions 162 | ---------------------- 163 | 164 | `/` is the identity function. 165 | 166 | 1 / dump 167 | 0000000000000001 168 | 169 | 170 | Recommended reading order 171 | ------------------------- 172 | 173 | * [how the input gets interpreted](parsing.md) 174 | * [where variables live](scopes.md) 175 | * [global functions](global.md) 176 | * [executing things](execution.md) 177 | * [function definition](quoting.md) 178 | * [containers other than arrays](container.md) 179 | * [some interfaces to the operating system](sys.md) 180 | * [error handling](err.md) 181 | * [coroutines](coroutines.md) 182 | * [naming conventions](conventions.md) 183 | * [ready-made TCP/IP server templates](server.md) 184 | * [foreign function interface](ffi.md) 185 | -------------------------------------------------------------------------------- /elymas/Makefile: -------------------------------------------------------------------------------- 1 | all: loaded shared 2 | 3 | shared: optimized shared.ey $(shell find lib -name '*.ey') 4 | ./optimized shared.ey 5 | 6 | loaded: optimized loaded.ey $(shell find lib -name '*.ey') 7 | ./optimized loaded.ey 8 | 9 | optimized: interpreter optimized.ey lib/math.ey lib/txt.ey lib/sys/opt.ey lib/sys/optroutines.ey 10 | ./interpreter optimized.ey 11 | 12 | .PHONY: all 13 | -------------------------------------------------------------------------------- /elymas/interpreter.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | { 4 | sys .argv len { 0 sys .argv * } { "/dev/stdin" } ? * include 5 | 0 sys .exit 6 | }' "interpreter" sys .freeze 7 | -------------------------------------------------------------------------------- /elymas/lib/bin.ey: -------------------------------------------------------------------------------- 1 | # The idea of bin is to define manipulation routines for strings used 2 | # as binary data structures 3 | 4 | < 5 | { 6 | { 8 uw } /u64 deffd 7 | { 4 uw } /u32 deffd 8 | { 2 uw } /u16 deffd 9 | { 1 uw } /u8 deffd 10 | { 8 sw } /s64 deffd 11 | { 4 sw } /s32 deffd 12 | { 2 sw } /s16 deffd 13 | { 1 sw } /s8 deffd 14 | { 8 unw } /un64 deffd 15 | { 4 unw } /un32 deffd 16 | { 2 unw } /un16 deffd 17 | { 1 unw } /un8 deffd 18 | { 8 snw } /sn64 deffd 19 | { 4 snw } /sn32 deffd 20 | { 2 snw } /sn16 deffd 21 | { 1 snw } /sn8 deffd 22 | }" /defBitVariants deffd 23 | 24 | < 25 | # 0 -> number of bytes to combine into unsigned int 26 | # 1 -> string 27 | # 0 <- first w bytes of string interpreted as unsigned int 28 | # 1 <- string from (w+1)th byte onwards 29 | { ==w ==s 30 | w s str .postfix 31 | [ 0 w range s each ] 256 math .unbase 32 | } /uw deffst 33 | 34 | # network byte order (i.e. big endian) 35 | { ==w ==s 36 | w s str .postfix 37 | [ 0 w range reverse s each ] 256 math .unbase 38 | } /unw deffst 39 | 40 | # TODO: signed parsing missing 41 | 42 | defBitVariants 43 | > /scan defvd 44 | 45 | < 46 | # 0 -> number of bytes to produce 47 | # 1 -> int to convert to bytes 48 | # 0 <- string enlengthened by binary encoded integer 49 | { ==w ==i 50 | w str .alloc ==s 51 | 0 w range { 0 -01 s =[] }" each 52 | i 256 math .base _ dom { -101*0 s =[] }" each -- 53 | s 54 | } /uw deffst 55 | 56 | # network byte order (i.e. big endian) 57 | { ==w ==i 58 | w str .alloc ==s 59 | 0 w range { 0 -01 s =[] }" each 60 | i 256 math .base _ dom { -101*0 w 1 sub -01 sub s =[] }" each -- 61 | s 62 | } /unw deffst 63 | 64 | # signed integers 65 | { ==w _ 0 lt { 1 w { 256 mul } rep add } rep 66 | w 67 | } _ |uw ; /sw deffst 68 | |unw ; /snw deffst 69 | 70 | defBitVariants 71 | > /produce defvd 72 | 73 | < 74 | { produce .uw cat } /uw deffst 75 | { produce .unw cat } /unw deffst 76 | { produce .sw cat } /sw deffst 77 | { produce .snw cat } /snw deffst 78 | defBitVariants 79 | > /print defvd 80 | > /bin defvd 81 | 82 | # vim: syn=elymas 83 | -------------------------------------------------------------------------------- /elymas/lib/err.ey: -------------------------------------------------------------------------------- 1 | < 2 | "" ==origWhat 3 | 4 | < > ==theHandler 5 | 6 | { 7 | theHandler sys .dyn .get not { < 8 | { "An unhandled error has occured, terminating program: " origWhat cat die } "" deffst 9 | > } rep 10 | } =*currentHandler 11 | 12 | { ==handler # ==what 13 | { handler -101 .? not } { _ len 1 sub -01 str .prefix } loop # TODO: actually strip one .xxx part 14 | handler -01 . 15 | } /applyHandler deffd 16 | 17 | # !!?, clones current coroutine state, useful in error handling, name follows intuitive understanding closely 18 | { { } { -- !!? } !!' } "!!?" 19 | 20 | { _ =origWhat # ==possibleActions 21 | currentHandler applyHandler 22 | } "???" 23 | 24 | { < > -01 ??? } "??" 25 | { { currentHandler applyHandler } currentHandler " " . theHandler sys .dyn .with } "??!" 26 | { { origWhat currentHandler applyHandler } currentHandler " " . theHandler sys .dyn .with } "??!'" 27 | { currentHandler < " " -11032 =* == >' theHandler sys .dyn .with } "?!" 28 | 29 | { ==what =*onErrorStrategy ==main 0 ==i 30 | { main { i onErrorStrategy =main i 1 add =i try } what ?! } _ =*try * 31 | } "?!!" 32 | > -- 7 |deffd rep 33 | 34 | # vim: syn=elymas 35 | -------------------------------------------------------------------------------- /elymas/lib/ffi.ey: -------------------------------------------------------------------------------- 1 | < 2 | { =*? }' /deff deffd 3 | { ==? }' /defv deffd 4 | > /ffi defv 5 | 6 | # vim: syn=elymas 7 | -------------------------------------------------------------------------------- /elymas/lib/ffi/gl.ey: -------------------------------------------------------------------------------- 1 | < 2 | sys .so ":" via 3 | txt .consume .|hu "%" defq 4 | 5 | "/usr/lib/x86_64-linux-gnu/libGL.so.1" :dlopen -- 6 | 7 | { _ "gl" -01 cat -1032 :resolveFunction -01 deffd }' "->" deffd 8 | 9 | %00001 ==:CURRENT_BIT 10 | %00002 ==:POINT_BIT 11 | %00004 ==:LINE_BIT 12 | %00008 ==:POLYGON_BIT 13 | %00010 ==:POLYGON_STIPPLE_BIT 14 | %00020 ==:PIXEL_MODE_BIT 15 | %00040 ==:LIGHTING_BIT 16 | %00080 ==:FOG_BIT 17 | %00100 ==:DEPTH_BUFFER_BIT 18 | %00200 ==:ACCUM_BUFFER_BIT 19 | %00400 ==:STENCIL_BUFFER_BIT 20 | %00800 ==:VIEWPORT_BIT 21 | %01000 ==:TRANSFORM_BIT 22 | %02000 ==:ENABLE_BIT 23 | %04000 ==:COLOR_BUFFER_BIT 24 | %08000 ==:HINT_BIT 25 | %10000 ==:EVAL_BIT 26 | %20000 ==:LIST_BIT 27 | %40000 ==:TEXTURE_BIT 28 | %80000 ==:SCISSOR_BIT 29 | %FFFFF ==:ALL_ATTRIB_BITS 30 | 31 | "ffff" "" ->ClearColor 32 | "i" "" ->Clear 33 | > /gl ffi .defv 34 | 35 | # vim: syn=elymas 36 | -------------------------------------------------------------------------------- /elymas/lib/ffi/gtk.ey: -------------------------------------------------------------------------------- 1 | # GTK+ support 2 | 3 | < 4 | sys .so ":" via 5 | 6 | "libgtk-3.so" :dlopen -- 7 | "libgdk-3.so" :dlopen -- 8 | "libatk-1.0.so" :dlopen -- 9 | "libgio-2.0.so" :dlopen -- 10 | "libpangocairo-1.0.so" :dlopen -- 11 | "libgdk_pixbuf-2.0.so" :dlopen -- 12 | "libcairo-gobject.so" :dlopen -- 13 | "libpango-1.0" :dlopen -- 14 | "libcairo.so" :dlopen -- 15 | "libgobject-2.0.so" :dlopen -- 16 | "libglib-2.0.so" :dlopen -- 17 | 18 | { _ "g_" -01 cat -1032 :resolveFunction -01 deffd }' "-->" deffd 19 | { _ "gtk_" -01 cat -1032 :resolveFunction -01 deffd }' "->" deffd 20 | 21 | # GC protection for callbacks 22 | map ==references 23 | { _ _ sys .asm .rawAddress txt .produce .u references =[] } /reference deffd 24 | 25 | "si" "p" ->application_new 26 | "p" "p" ->application_window_new 27 | 28 | "pip" "i64" -->application_run 29 | "p" "" -->application_quit 30 | "p" "" -->object_unref 31 | { -2103 "pp" "" :wrapCallback reference -0321 } "g_signal_connect_data" "pscppi" "" :resolveFunction ; /signal_connect_data deffd 32 | 33 | "pp" "" ->container_add 34 | "pi" "" ->container_set_border_width 35 | 36 | "p" "" ->widget_show_all 37 | "p" "" ->widget_destroy 38 | "pi" "" ->widget_set_hexpand 39 | "pi" "" ->widget_set_vexpand 40 | 41 | "" "p" ->grid_new 42 | "ppiiii" "" ->grid_attach 43 | 44 | "pp" "p" ->scrolled_window_new 45 | 46 | "ps" "" ->window_set_title 47 | "pii" "" ->window_set_default_size 48 | 49 | "i" "p" ->button_box_new 50 | "s" "p" ->button_new_with_label 51 | 52 | "" "p" ->text_view_new 53 | "pi" "" ->text_view_set_editable 54 | "pi" "" ->text_view_set_cursor_visible 55 | "p" "p" ->text_view_get_buffer 56 | 57 | { _ len } "gtk_text_buffer_set_text" "psi" "" :resolveFunction ; /text_buffer_set_text deffd 58 | 59 | 0 ==:ORIENTATION_HORIZONTAL 60 | 1 ==:ORIENTATION_VERTICAL 61 | 62 | 2 ==:CONNECT_SWAPPED 63 | > /gtk ffi .defv 64 | 65 | # vim: syn=elymas 66 | -------------------------------------------------------------------------------- /elymas/lib/ffi/pq.ey: -------------------------------------------------------------------------------- 1 | # PostgreSQL support 2 | 3 | < 4 | sys .so ":" via 5 | 6 | "libpq.so" :dlopen -- 7 | 8 | { "PQ" -01 cat -021 -210 :resolveFunction }' "=>" deffd 9 | { _ "PQ" -01 cat -1032 :resolveFunction -01 deffd }' "->" deffd 10 | 11 | # connection setup and teardown 12 | "s" "p" ->connectdb 13 | "p" "" ->finish 14 | 15 | # connection parameter getters 16 | "p" "s" ->db 17 | "p" "s" ->user 18 | "p" "s" ->host 19 | "p" "s" ->port 20 | "p" "s" ->options 21 | 22 | 0 ==:CONNECTION_OK 23 | 1 ==:CONNECTION_BAD 24 | "p" "u32" ->status 25 | 26 | 0 ==:TRANS_IDLE 27 | 1 ==:TRANS_ACTIVE 28 | 2 ==:TRANS_INTRANS 29 | 3 ==:TRANS_INERROR 30 | 4 ==:TRANS_UNKNOWN 31 | "p" "u32" ->transactionStatus 32 | 33 | { -01 } "ps" "s" =>parameterStatus ; /parameterStatus deffd 34 | 35 | "p" "s" ->errorMessage 36 | 37 | "p" "u32" ->socket 38 | "p" "u32" ->backendPID 39 | 40 | # 0 -> connection 41 | # 1 -> statement SQL text 42 | # 0 <- result 43 | { -01 } "ps" "p" =>exec ; /exec deffd 44 | 45 | # 0 -> connection 46 | # 1 -> statement SQL text 47 | # 2 -> paramCount 48 | # 3 ... -> parameters (last one at 3) 49 | # 0 <- result 50 | < 51 | "psiibiii" "p" =>execParams =*:internalExecParams 52 | { ==con ==sql ==paramCount 53 | paramCount 8 mul str .alloc ==paramValues 54 | paramValues :rawContentAddress paramCount 8 mul add ==i 55 | [ ] ==saveFromGC 56 | 57 | paramCount { _ sys .typed .type ==t 58 | i 8 sub =i 59 | [ 60 | { t 0 eq }' { txt .produce .u "\0" cat }' 61 | { t 1 eq }' { "\0" cat }' 62 | { 1 }' { "unsupported parameter type" die } 63 | ] conds 64 | _ [ -01 ] saveFromGC cat =saveFromGC 65 | 66 | :rawContentAddress i :mem .produce .u64 67 | } rep 68 | 69 | con 70 | sql 71 | paramCount 72 | 0 # all parameters implicitely typed 73 | paramValues 74 | 0 # all parameters passed as text 75 | 0 # all parameters passed as text 76 | 0 # text results requested 77 | internalExecParams 78 | } 79 | > -- /execParams deffd 80 | 81 | # 0 -> connection 82 | # 1 -> statement name 83 | # 2 -> statement SQL text 84 | # 0 <- result 85 | { 0 -12300 } "pssii" "p" =>prepare ; /prepare deffd 86 | 87 | 0 ==:EMPTY_QUERY 88 | 1 ==:COMMAND_OK 89 | 2 ==:TUPLES_OK 90 | 3 ==:COPY_OUT 91 | 4 ==:COPY_IN 92 | 5 ==:BAD_RESPONSE 93 | 6 ==:NONFATAL_ERROR 94 | 7 ==:FATAL_ERROR 95 | 8 ==:COPY_BOTH 96 | 9 ==:SINGLE_TUPLE 97 | 98 | "p" "u32" ->resultStatus 99 | "i" "s" ->resStatus 100 | "p" "s" ->resultErrorMessage 101 | 102 | # 0 -> result 103 | "p" "" ->clear 104 | 105 | "p" "i32" ->ntuples 106 | "p" "i32" ->nfields 107 | 108 | { -01 } "pi" "s" =>fname ; /fname deffd 109 | { -01 } "ps" "i32" =>fnumber ; /fnumber deffd 110 | 111 | # 0 -> result 112 | # 1 -> row number 113 | # 2 -> column number 114 | # 0 <- value 115 | { -021 } "pii" "s" =>getvalue ; /getvalue deffd 116 | 117 | # 0 -> result 118 | # 1 -> row number 119 | # 2 -> column number 120 | # 0 <- 1 if the field is null 121 | { -021 } "pii" "u32" =>getisnull ; /getisnull deffd 122 | 123 | "p" "s" ->cmdStatus 124 | "p" "s" ->cmdTuples 125 | 126 | # 0 -> connection 127 | # 1 -> encoding 128 | # 0 <- 0 on success 129 | { -01 } "ps" "i32" =>setClientEncoding ; /setClientEncoding deffd 130 | 131 | # object oriented interface 132 | "s" "p" =>connectdb { ==con < 133 | [ 134 | /finish /db /user /host /port /options /status /transactionStatus 135 | /parameterStatus /errorMessage /socket /backendPID 136 | /prepare 137 | /setClientEncoding 138 | ] { 139 | { con } ffi .pq -2102 .| ; -01 deffst 140 | }' each 141 | 142 | |errorMessage /error deffst 143 | 144 | [ 145 | /exec /execParams /prepare 146 | ] { 147 | { con } ffi .pq -2102 .| ; { ==res < 148 | [ 149 | /resultStatus /resultErrorMessage 150 | /clear /ntuples /nfields /fname /fnumber 151 | /getvalue /getisnull /cmdStatus /cmdTuples 152 | ] { 153 | { res } ffi .pq -2102 .| ; -01 deffst 154 | }' each 155 | 156 | |resultErrorMessage /error deffst 157 | |resultStatus /status deffst 158 | |resultStatus |resStatus ; /strStatus deffst 159 | 160 | { 161 | 0 nfields range ==fieldRange 162 | [ fieldRange { fname } each ] =*fieldNames 163 | [ 0 ntuples range { ==r 164 | < 165 | fieldRange { == }' { =*def ==c 166 | r c getvalue c fieldNames def 167 | }_ each 168 | > 169 | } each ] 170 | } /all deffst 171 | > } ; -01 deffst 172 | }' each 173 | > } ; /connect deffd 174 | 175 | { 176 | connect ==con 177 | con .status { < 178 | con .errorMessage ==msg 179 | > ???io.ffi.pq } rep 180 | 181 | { # ==nsQuery 182 | "" ==spaceQuery 183 | { _ "([^ ]*) (.*)" regex } { -102 -- 184 | spaceQuery -01 cat " " cat =spaceQuery 185 | } loop spaceQuery -01 cat =spaceQuery 186 | spaceQuery ==parameterCountTmp 187 | 0 ==maxParameter 188 | { parameterCountTmp "^(.*)\\$(\\d+)(.*)$" regex } { ==a ==p ==b 189 | a b cat =parameterCountTmp 190 | p txt .consume .u maxParameter max =maxParameter 191 | } loop 192 | 193 | maxParameter { 194 | maxParameter spaceQuery con .execParams 195 | } { 196 | spaceQuery con .exec 197 | } ? * ":-" via 198 | [ 199 | { :-status |COMMAND_OK eq }' { :-clear }' 200 | { :-status |TUPLES_OK eq }' { :-all :-clear }' 201 | { 1 }' { < :-error ==msg > ???io.ffi.pq } 202 | ] conds 203 | } 204 | } /functional deffd 205 | > /pq ffi .defv 206 | 207 | # vim: syn=elymas 208 | -------------------------------------------------------------------------------- /elymas/lib/ffi/sdl.ey: -------------------------------------------------------------------------------- 1 | < 2 | sys .so ":" via 3 | 4 | "/usr/lib/x86_64-linux-gnu/libSDL2.so" :dlopen -- 5 | 6 | 32 ==:INIT_VIDEO 7 | 8 | { _ "SDL_" -01 cat -1032 :resolveFunction -01 deffd }' "->" deffd 9 | 10 | "" "" ->SetMainReady 11 | "i" "i32" ->Init 12 | "" "" ->Quit 13 | "" "s" ->GetError 14 | 15 | 1 ==:WINDOW_FULLSCREEN 16 | 2 ==:WINDOW_OPENGL 17 | 4 ==:WINDOW_SHOWN 18 | 8 ==:WINDOW_HIDDEN 19 | 16 ==:WINDOW_BORDERLESS 20 | 32 ==:WINDOW_RESIZABLE 21 | 64 ==:WINDOW_MINIMIZED 22 | 128 ==:WINDOW_MAXIMIZED 23 | 256 ==:WINDOW_INPUT_GRABBED 24 | 512 ==:WINDOW_INPUT_FOCUS 25 | 1024 ==:WINDOW_MOUSE_FOCUS 26 | 2048 ==:WINDOW_FOREIGN 27 | 4097 ==:WINDOW_FULLSCREEN_DESKTOP 28 | 29 | "siiiii" "p" ->CreateWindow 30 | "p" "" ->DestroyWindow 31 | "p" "i32" ->UpdateWindowSurface 32 | "p" "p" ->GetWindowSurface 33 | "pbi" "i32" ->FillRect 34 | { 0 -201 } /SDL_FillRect "pii" "i32" :resolveFunction ; /Fill deffd 35 | 36 | 37 | 0 ==:GL_RED_SIZE 38 | 1 ==:GL_GREEN_SIZE 39 | 2 ==:GL_BLUE_SIZE 40 | 3 ==:GL_ALPHA_SIZE 41 | 4 ==:GL_BUFFER_SIZE 42 | 5 ==:GL_DOUBLEBUFFER 43 | 6 ==:GL_DEPTH_SIZE 44 | 7 ==:GL_STENCIL_SIZE 45 | 8 ==:GL_ACCUM_RED_SIZE 46 | 9 ==:GL_ACCUM_GREEN_SIZE 47 | 10 ==:GL_ACCUM_BLUE_SIZE 48 | 11 ==:GL_ACCUM_ALPHA_SIZE 49 | 12 ==:GL_STEREO 50 | 13 ==:GL_MULTISAMPLEBUFFERS 51 | 14 ==:GL_MULTISAMPLESAMPLES 52 | 15 ==:GL_ACCELERATED_VISUAL 53 | 16 ==:GL_RETAINED_BACKING 54 | 17 ==:GL_CONTEXT_MAJOR_VERSION 55 | 18 ==:GL_CONTEXT_MINOR_VERSION 56 | 19 ==:GL_CONTEXT_EGL 57 | 20 ==:GL_CONTEXT_FLAGS 58 | 21 ==:GL_CONTEXT_PROFILE_MASK 59 | 22 ==:GL_SHARE_WITH_CURRENT_CONTEXT 60 | 61 | "ii" "i32" ->GL_SetAttribute 62 | "p" "p" ->GL_CreateContext 63 | "p" "" ->GL_SwapWindow 64 | "p" "" ->GL_DeleteContext 65 | 66 | SetMainReady 67 | > /sdl ffi .defv 68 | 69 | # vim: syn=elymas 70 | -------------------------------------------------------------------------------- /elymas/lib/list.ey: -------------------------------------------------------------------------------- 1 | < 2 | [ ] ==:NONE 3 | 0 ==l # placeholder, zero value is never read 4 | 5 | { -102 .len -021 ? }" "#?" defmd 6 | { .len }" "#len" defmd 7 | { 0 -01 .len range }" "#dom" defmd 8 | { [ 0 ] }" _ "#in" deffd "#out" deffd 9 | { ==m ==l 10 | l .len { 11 | l .start l .len 1 sub { 1 -01 * } rep 12 | m .start 1 -102 =[] 13 | l .len m .len add l .setLen 14 | } { 15 | m .start l .setStart m .len l .setLen 16 | } ? * 17 | m .end l .setEnd 18 | 19 | 0 m .setLen 20 | NONE m .setStart 21 | NONE m .setEnd 22 | 23 | l 24 | # FIXME think hard whether cat should be destructive 25 | } "#cat" defmd 26 | { ==l =*f 27 | l .start ==n 28 | l .len { n 2 dearray =n f }" rep 29 | } "#each" defmd 30 | { l .len mod ==i 31 | l .start i { 1 -01 * } rep 32 | 0 -01 * 33 | } '0.0 /access deffd 34 | { =l access } "#*" defmd 35 | { ==l ==i ==v 36 | l .len not { "=[] into empty list" die } rep 37 | l .start i l .len mod { 1 -01 * } rep 38 | v 0 -102 =[] 39 | } "#=[]" defmd 40 | { ==l 41 | list ==m 42 | l .len { 43 | [ 0 NONE ] _ m .setEnd 44 | l .len 1 sub { [ 0 -102 ] } rep 45 | m .setStart 46 | l .len m .setLen 47 | } { } ? * 48 | m 49 | } "#iclone" defmd 50 | { 0 }" "#istart" deffd 51 | { .len eq }" "#iend" defmd 52 | { }" "#itrans" deffd 53 | { 1 add }" "#istep" deffd 54 | 55 | { =l [ -01 NONE ] 56 | l .len { 57 | _ 1 l .end =[] 58 | }" { 59 | _ l .setStart 60 | }" ? * 61 | l .setEnd 62 | l .len 1 add l .setLen 63 | }' /append1 defmd 64 | 65 | { =l 66 | l .len 2 ge { 67 | l .start 68 | l .len _ 1 sub l .setLen 69 | 2 sub { 1 -01 * } rep 70 | _ l .setEnd 71 | NONE 1 -102 =[] 72 | } { 73 | 0 l .setLen 74 | NONE l .setStart 75 | NONE l .setEnd 76 | } ? * 77 | }' /pop defmd 78 | 79 | { { .append1 }_ '0. * } /append defmd 80 | 81 | { < 82 | 0 ==len { =len }' =*setLen 83 | NONE ==start { =start }' =*setStart 84 | NONE ==end { =end }' =*setEnd 85 | > }' 86 | > -- /list deffd 87 | 88 | # vim: syn=elymas 89 | -------------------------------------------------------------------------------- /elymas/lib/map.ey: -------------------------------------------------------------------------------- 1 | { { defv }' scope } 2 | < 3 | /generate deffd 4 | 0 ==m # placeholder, zero value is never read 5 | { m .v -01 . }' [ 0 ] [ 0 ] '' /access deffd 6 | { =m access }' "#*" defmd 7 | { [ 0 ] }" "#in" deffd 8 | { [ 0 ] }" "#out" deffd 9 | { =m m .v keys }' "#dom" defmd 10 | { =m m .v ==v =*f v keys { v -01 . f }' each } "#each" defmd 11 | { 0 } "#istart" deffd 12 | { =m m .v keys len eq }' "#iend" defmd 13 | { 1 add }" "#istep" deffd 14 | { =m m .v keys * }' "#itrans" defmd 15 | { =m m .v -01 .?' }' /has defmd 16 | { =m m .v ==v "#iclone" | * ==n v keys { _ v -01 . -01 n =[] } each n }' /clone defmd 17 | { < generate ==v "#=[]" =* > }' _ "#iclone" deffd 18 | > -- /map deffd 19 | 20 | # vim: syn=elymas 21 | -------------------------------------------------------------------------------- /elymas/lib/math.ey: -------------------------------------------------------------------------------- 1 | # Discrete mathematics useful in computer stuff 2 | # More complicated stuff in sublibs 3 | 4 | < 5 | # converts an array of digits into an integer 6 | # i.e. [ 1 2 3 ] 10 unbase => 321 7 | # i.e. [ ] 10 unbase => 0 8 | # 0 -> base to convert from 9 | # 1 -> array of digits 10 | # 0 <- resulting integer 11 | { ==b 12 | _ len _ ==l dearray 13 | 0 l { b mul add } rep 14 | } /unbase deff 15 | 16 | # converts an integer into an array of digits 17 | # i.e. 123 10 base => [ 3 2 1 ] 18 | # i.e. 0 10 base => [ ] 19 | # 0 <- base to convert to 20 | # 1 <- integer to convert 21 | # 0 -> resulting array of digits 22 | { ==b 23 | [ -01 { _ } { _ b mod -01 b div } loop -- ] 24 | } /base deff 25 | > /math defv 26 | 27 | # FIXME: INTEGRATE 28 | # # 0 -> float 29 | # # 0 <- the int portion of the float, rounded towards zero 30 | # [[ 31 | # /rbx :popqReg 32 | # 33 | # # allocate result int 34 | # ::internalAllocateInteger /rax :movqImmReg 35 | # /rax :callqReg 36 | # 37 | # # actual conversion 38 | # /rcx :popqReg 39 | # 8 /rcx :fld64MemDisp8 40 | # 8 /rax :fistp64MemDisp8 41 | # 42 | # # push int on program stack 43 | # /rax :pushqReg 44 | # 45 | # /rbx :pushqReg 46 | # :retn 47 | # ]] /eytrunc defv 48 | 49 | # vim: syn=elymas 50 | -------------------------------------------------------------------------------- /elymas/lib/net.ey: -------------------------------------------------------------------------------- 1 | < 2 | { =*? }' /deff deffd 3 | { ==? }' /defv deffd 4 | > /net defv 5 | 6 | # vim: syn=elymas 7 | -------------------------------------------------------------------------------- /elymas/lib/net/alg.ey: -------------------------------------------------------------------------------- 1 | < 2 | { =*? }' /deff deffd 3 | { ==? }' /defv deffd 4 | > /alg net .defv 5 | 6 | # vim: syn=elymas 7 | -------------------------------------------------------------------------------- /elymas/lib/net/alg/http.ey: -------------------------------------------------------------------------------- 1 | # provide a http server 2 | { < 3 | net .alg .bufferedEpollServer "^" via 4 | 5 | < 6 | { "request unconfigured (of rawHttpServer)" die } /request deffst 7 | { 4096 } /inputBufferLimit deffst 8 | 9 | { = }' /set deffst 10 | { scope keys }' /setters deffst 11 | { _ ^settings .installSetters =*install 12 | setters { _ { set }_ -01 install }" each 13 | } /installSetters deffst 14 | > _ ==settings "::" via 15 | 16 | { -10 deffst }' ::installSetters 17 | 18 | { ":" via "" ==url "" ==method < { defvst }' /put deffst > ==headers "" ==body 19 | { 20 | method url headers body < ==body ==headers ==url ==method 21 | [ ] ==outputHeaders 22 | { :close } =*close 23 | { :write } =*write 24 | { :finish } =*finish 25 | { ==contentType 26 | "HTTP/1.0 200 Ok\r\nContent-Type: " contentType cat "\r\n" cat 27 | outputHeaders |cat each 28 | "\r\n" cat -01 cat :write :finish 29 | } =*ok 30 | { ==contentType 31 | "HTTP/1.0 500 Error\r\nContent-Type: " contentType cat "\r\n" cat 32 | outputHeaders |cat each 33 | "\r\n" cat -01 cat :write :finish 34 | } =*fail 35 | { [ -01 "\r\n" cat ] outputHeaders -01 cat =outputHeaders } =*addHeader 36 | > ::request 37 | } =*requestParsed 38 | 39 | < 40 | { :close } _ =*err =*end 41 | { ==inBuffer 42 | { inBuffer "\n" regex } { [ 43 | { inBuffer len ::inputBufferLimit gt } { "" =inBuffer :close } 44 | { inBuffer "^(GET|POST) ([^\r\n]*) HTTP/\\d\\.\\d\r?\n(.*)" regex } { =method =url =inBuffer } 45 | { inBuffer "^([^:\r\n]+): ([^\r\n]*)\r?\n(.*)" regex } { headers .put =inBuffer } 46 | { inBuffer "^\r?\n(.*)" regex } { =inBuffer 47 | headers .?Content-Length not { 48 | requestParsed 49 | } { 50 | headers .Content-Length "^\\d+$" regex not { 51 | "" =inBuffer :close 52 | } { 53 | headers .Content-Length txt .consume .u ==contentLength 54 | 55 | { body -01 cat =body 56 | body len _ ::inputBufferLimit gt { "" =body :close } rep 57 | contentLength ge { 58 | contentLength body str .postfix ==afterBody 59 | contentLength body str .prefix =body 60 | requestParsed 61 | 62 | afterBody 63 | } { 64 | "" 65 | } ? * 66 | } =in 67 | 68 | inBuffer in =inBuffer 69 | } ? * 70 | } ? * 71 | } 72 | { 1 } { 73 | "HTTP/1.0 400 Error\r\nContent-Type: text/html\r\n\r\nCould not parse request\r\n" 74 | :write :finish "" =inBuffer 75 | } 76 | ] conds } loop inBuffer } =*in 77 | > 78 | } ^accept 79 | 80 | { 81 | { ^run } { 82 | _ .?close { .close } { ??!' } ? * 83 | } ?!io.net 84 | } /run deffst 85 | > } /rawHttpServer net .alg .deff 86 | 87 | { < 88 | net .alg .rawHttpServer "^" via ^settings "::" via 89 | 90 | < 91 | { "request unconfigured (of httpServer)" die } /request deffst 92 | 93 | { = }' /set deffst 94 | { scope keys }' /setters deffst 95 | { _ ^settings .installSetters =*install 96 | setters { _ { set }_ -01 install }" each 97 | } /installSetters deffst 98 | > _ ==settings "::" via 99 | 100 | { -10 deffst }' ::installSetters 101 | 102 | { _ ==req ":" via 103 | < { defvst }' > ==args { net .alg .uri .percentEncoding .|consume -30*20*1* }_ =*setArg 104 | :url _ ==url 105 | "^([^?]*)\\?(.*)$" regex { 106 | =url "&" str .split { _ ==arg 107 | "^([^=]*)=(.*)$" regex not { "" arg } rep 108 | setArg 109 | } each 110 | } rep 111 | 112 | url args < ==args ==url req >' ::request 113 | } ^request 114 | 115 | { ^run } /run deffst 116 | > } /httpServer net .alg .deff 117 | 118 | # vim: syn=elymas 119 | -------------------------------------------------------------------------------- /elymas/lib/net/alg/server.ey: -------------------------------------------------------------------------------- 1 | # provide a standard epoll-based tcp/ip server 2 | < 3 | { ==err _ 0 lt { err ?? } rep } "+??" deffd 4 | { ==err ==actions _ 0 lt { actions err ??? } rep } "+???" deffd 5 | 6 | { < 7 | sys .linux "+" via +epoll "++" via 8 | sys .asm "+!" via 9 | net .tcp "+:" via 10 | 11 | < 12 | { 1 } /running deffst 13 | { 1000000 } /interval deffst 14 | { "unconfigured accept (of epollServer)" die } /accept deffst 15 | { "unconfigured port (of epollServer)" die } /port deffst 16 | { 1 -01 +setsockopt .reuseAddr +??io.net.setsockopt -- } /reuseAddr deffst 17 | { -- } /afterListen deffst 18 | 19 | { = }' /set deffst 20 | { scope keys }' /setters deffst 21 | { =*install 22 | setters { _ { set }_ -01 install }" each 23 | } /installSetters deffst 24 | > _ ==settings "::" via 25 | 26 | { deffst }' ::installSetters 27 | 28 | < > ==:noHandler 29 | 30 | { 31 | ::port { ==s 32 | s ::reuseAddr 33 | s +FGETFL 0 +fcntl +??io.net.fcntl.get +ONONBLOCK bor ==flags 34 | s +FSETFL flags +fcntl +??io.net.fcntl.set -- 35 | } +:listenOptFd _ ::afterListen ==listenFd 36 | 37 | [ ] ==allEventHandlers 38 | { ==fd ==handler 39 | { allEventHandlers len fd le }' { 40 | allEventHandlers [ noHandler ] cat =allEventHandlers 41 | } loop 42 | handler fd allEventHandlers =[] 43 | } /protectGC deffst 44 | { ==fd noHandler fd allEventHandlers =[] } /unprotectGC deffst 45 | 46 | < 47 | { 48 | listenFd +accept ==fd 49 | fd 0 lt { 50 | +errno +EAGAIN neq { ??io.net.accept } rep 51 | } { 52 | noHandler ==eventHandler 53 | ++EPOLLIN ++EPOLLERR bor ==initialFlags 54 | 0 ==closed 55 | 56 | < 57 | { 58 | closed not { 59 | epoll ++EPOLLCTLDEL fd 0 0 ++ctl +??io.net.epoll -- 60 | fd +close +??io.net.close -- 61 | fd unprotectGC 62 | 1 =closed 63 | } rep 64 | } /close deffst 65 | { ==count 66 | closed { "" } { 67 | count str .alloc ==buf 68 | fd buf count +read 69 | |close < { 0 } ; =*close > +???io.net.con.read 70 | buf str .inplacePrefix 71 | } ? * 72 | } /read deff 73 | { ==buf 74 | closed { buf len } { 75 | fd buf _ len +write 76 | |close < =*close > +???io.net.con.write 77 | } ? * 78 | } /write deff 79 | { ==flags 80 | closed not { 81 | eventHandler +!rawAddress noHandler +!rawAddress eq { 82 | flags =initialFlags 83 | } { 84 | epoll ++EPOLLCTLMOD fd flags eventHandler +!rawAddress ++ctl +??io.net.epoll -- 85 | } ? * 86 | } rep 87 | } /ctl deffst 88 | > ::accept =eventHandler 89 | 90 | epoll ++EPOLLCTLADD fd initialFlags eventHandler +!rawAddress ++ctl +??io.net.epoll -- 91 | eventHandler fd protectGC 92 | } ? * 93 | } =*in 94 | { "unexpected output capability on listening socket" die } =*out 95 | { ??io.net } =*err 96 | > ==listenFdEventHandler 97 | 98 | listenFdEventHandler listenFd protectGC 99 | 100 | ++create +??io.net.epoll ==epoll 101 | epoll ++EPOLLCTLADD listenFd ++EPOLLIN listenFdEventHandler +!rawAddress ++ctl +??io.net.epoll -- 102 | 103 | { ::running } { 104 | epoll 16 ::interval ++wait +??io.net.wait -- 105 | { 106 | _ .data +!rawObject ":" via 107 | .events 108 | _ ++EPOLLIN band not not { :in } rep 109 | _ ++EPOLLOUT band not not { :out } rep 110 | ++EPOLLERR band not not { :err } rep 111 | } each 112 | } loop 113 | } /run deffst 114 | > } /epollServer net .alg .deff 115 | 116 | { < 117 | net .alg .epollServer "^" via 118 | 119 | < 120 | { "unconfigured accept (of bufferedEpollServer)" die } /accept deffst 121 | { 1048576 } /outputBufferLimit deffst 122 | 123 | { = }' /set deffst 124 | { scope keys }' /setters deffst 125 | { _ ^settings .installSetters =*install 126 | setters { _ { set }_ -01 install }" each 127 | } /installSetters deffst 128 | > _ ==settings "::" via 129 | 130 | { deffst }' ::installSetters 131 | 132 | sys .linux .epoll "++" via 133 | 134 | { ":" via "" ==inBuffer "" ==outBuffer 0 ==finished 135 | < 136 | { 137 | outBuffer -01 cat _ =outBuffer 138 | len ::outputBufferLimit gt { 139 | |close < =*close 140 | { ::outputBufferLimit 2 mul outputBufferLimit } =*increase 141 | > ???limit.io.out 142 | } rep 143 | ++EPOLLOUT ++EPOLLIN ++EPOLLERR bor bor :ctl 144 | } =*write 145 | { :close } =*close 146 | { 1 =finished } =*finish 147 | > ::accept ":::" via < 148 | { 149 | 4096 :read _ len 150 | { inBuffer -01 cat :::in =inBuffer } 151 | { -- :::end } 152 | ? * 153 | } =*in 154 | { 155 | outBuffer _ :write -01 str .postfix 156 | _ =outBuffer 157 | len _ { ++EPOLLOUT } { 0 } ? * ++EPOLLIN ++EPOLLERR bor bor :ctl 158 | not finished and { :close } rep 159 | } =*out 160 | { :::err } =*err 161 | > 162 | } ^accept 163 | 164 | { ^run } /run deffst 165 | > } /bufferedEpollServer net .alg .deff 166 | > -- 167 | 168 | # vim: syn=elymas 169 | -------------------------------------------------------------------------------- /elymas/lib/net/alg/uri.ey: -------------------------------------------------------------------------------- 1 | # provide helper function for URI coding 2 | < 3 | < 4 | { _ 37 eq { -- { { decode }_ } } { unencoded } ? * } ==:unencoded 5 | { { 48 sub txt .consume .hexDigitsReverse } -20*10* 16 mul add unencoded } =*:decode 6 | 7 | { # ==s 8 | [ unencoded -102 { -01 * } each -- ] str .fromArray 9 | } /consume deffd 10 | 11 | [ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~" { } each ] ==:unencodedChars 12 | 13 | { # ==s 14 | [ -01 { _ unencodedChars neq all { 37 -01 _ 16 div -01 16 mod "0123456789ABCDEF" -20*10* } rep } each ] str .fromArray 15 | } /produce deffd 16 | > /percentEncoding defv 17 | > /uri net .alg .defv 18 | 19 | # vim: syn=elymas 20 | -------------------------------------------------------------------------------- /elymas/lib/net/dns.ey: -------------------------------------------------------------------------------- 1 | # Provide nice ways to do DNS resolution 2 | # Spec: http://www.faqs.org/rfcs/rfc1035.html 3 | 4 | < 5 | { ==err _ 0 lt { err ?? } rep } "+??" deffd 6 | { ==err ==actions _ 0 lt { actions err ??? } rep } "+???" deffd 7 | 8 | # Uncomment to enable function ("deffd") tracing for this scope 9 | # { 10 | # -010 { " executing" cat dump }_ -01 ; -01 =*: 11 | # }" /deffd deffd 12 | 13 | bin .scan "->" via 14 | bin .print "<-" via 15 | bin .produce "<=" via 16 | sys .linux "+" via 17 | 18 | # 0 -> ascii ip address 19 | # 0 <- ipv4 address as un32 20 | { [ -01 "^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$" regex not { "not an IPv4 address" die } rep ] 21 | txt .consume .u reverse str .fromArray 22 | } /parseIpv4 deffd 23 | 24 | # 0 -> hostname 25 | # 0 <- ipv4 address as un32 26 | { ==host 27 | ensureResolvConf 28 | resolvConf .nameserver parseIpv4 53 net .udp .sockaddrIpv4 29 | +AFINET +SOCKDGRAM +IPPROTOUDP +socket +??io.net.socket _ ==s 30 | -01 +connect +??io.net.connect -- 31 | 32 | s 33 | host buildDnsQueryMessage 34 | _ len 35 | +write +??io.net.write -- # TODO: correctly handle non-full writes 36 | 37 | 1024 str .alloc ==buf 38 | 39 | s 40 | buf 41 | _ len 42 | +read +??io.net.read 43 | buf str .inplacePrefix =buf 44 | 45 | buf 46 | ->un16 ==id # expected to be zero 47 | ->u16 2 math .base ==bitfields 48 | ->un16 ==qdCount 49 | ->un16 ==anCount 50 | ->un16 ==nsCount # expected to be zero 51 | ->un16 ==arCount # expected to be zero 52 | 53 | qdCount { 54 | ->u8 ==labelLength 55 | { labelLength } { 56 | labelLength 64 ge { 57 | "unexpected compression pointer in DNS reply" die 58 | } { 59 | labelLength -01 str .postfix 60 | ->u8 =labelLength 61 | } ? * 62 | } loop 63 | ->un16 ==qType 64 | ->un16 ==qClass 65 | } rep 66 | 67 | # _ |dump each 68 | 69 | anCount { 70 | ->u8 ==labelLength 71 | { labelLength } { 72 | labelLength 64 ge { 73 | ->u8 labelLength 63 band 256 mul add ==pointerTarget # TODO actually care for pointer target 74 | 0 =labelLength 75 | } { 76 | labelLength -01 str .postfix 77 | ->u8 =labelLength 78 | } ? * 79 | } loop 80 | 81 | ->un16 1 eq not { "Answer type field was not 'A'" die } rep 82 | ->un16 1 eq not { "Answer class field was not 'INET'" die } rep 83 | ->un32 -- # _ ==ttl "TTL: " dump dump 84 | ->un16 4 eq not { "Answer data length was not 4" die } rep 85 | 4 -01 str .inplacePrefix # 4 byte IP data to be returned 86 | } { 87 | "Answer did not contain any answer data" die 88 | } ? * 89 | } /resolveIpv4 deffd 90 | 91 | # 0 -> hostname 92 | # 0 <- dns query message 93 | { ==host 94 | 0 <=un16 # id 95 | [ 1 0 0 0 0 0 0 0 ] 2 math .unbase <-u8 # QR Opcode*4 AA TC RD 96 | [ 0 0 0 0 0 0 0 0 ] 2 math .unbase <-u8 # RA Z*3 RCODE*4 97 | 1 <-un16 # qdcount 98 | 0 <-un16 # ancount 99 | 0 <-un16 # nscount 100 | 0 <-un16 # arcount 101 | ==query 102 | 103 | host { "^([^.]+)\\.?(.*)" regex } { 104 | makeLabel query -01 cat =query 105 | } loop 106 | 107 | query 108 | "\0" cat 109 | 110 | 1 <-un16 # "A" query 111 | 1 <-un16 # "Internet" QCLASS 112 | } /buildDnsQueryMessage deffd 113 | 114 | # 0 -> string 115 | # 0 <- string with u8 length prepended 116 | { _ len <=u8 -01 cat } /makeLabel deffd 117 | 118 | # 0 -> dns message 119 | # 0 <- dns message with tcp transport header prepended 120 | { _ len <=u16 -01 cat } /prepareTcpMessage deffd 121 | 122 | < 123 | 0 ==?loaded 124 | { defv }' /put deffd 125 | > /resolvConf defvd 126 | 127 | # ensure resolv.conf is parsed 128 | { 129 | resolvConf .loaded not { 130 | { [ 131 | { _ "^[ ]*nameserver[ ]+(.*)" regex } { /nameserver resolvConf .put } 132 | ] conds -- } 133 | "/etc/resolv.conf" sys .file ":" via :open :eachLine :close 134 | 135 | 1 /loaded resolvConf .put 136 | } rep 137 | } /ensureResolvConf deffd 138 | > /dns net .defv 139 | 140 | # vim: syn=elymas 141 | -------------------------------------------------------------------------------- /elymas/lib/net/tcp.ey: -------------------------------------------------------------------------------- 1 | # Provide nice ways to do TCP/IP networking 2 | 3 | < 4 | { ==err _ 0 lt { err ?? } rep } "+??" deffd 5 | { ==err ==actions _ 0 lt { actions err ??? } rep } "+???" deffd 6 | 7 | bin .scan "->" via 8 | bin .print "<-" via 9 | bin .produce "<=" via 10 | sys .linux "+" via 11 | 12 | # 0 -> port 13 | # 1 -> host (as network byte ordered string) 14 | # 0 <- string representing the sockaddr_in 15 | { ==port ==host 16 | +AFINET <=u16 17 | port <-un16 18 | host cat 19 | 0 <-un64 20 | } /sockaddrIpv4 deffd 21 | 22 | # TODO: use this in the code below (and test) 23 | # 0 <- new tcp socket fd 24 | { 25 | +AFINET +SOCKSTREAM +IPPROTOTCP +socket +??io.net.socket 26 | } _ /socketFd deffd 27 | /socket deffd 28 | 29 | # 0 -> "host:port" 30 | # 0 <- connected socket fd 31 | { "^([^:]+):(\\d+)$" regex not { "host:port expected" die } rep 32 | net .dns .resolveIpv4 33 | -01 txt .consume .u 34 | sockaddrIpv4 35 | +AFINET +SOCKSTREAM +IPPROTOTCP +socket +??io.net.socket _ ==s 36 | -01 +connect +??io.net.connect -- 37 | s 38 | } /connectFd deffd 39 | 40 | # 0 -> "host:port" 41 | # 0 <- connected socket as file 42 | { 43 | connectFd sys .fdToFile 44 | } /connect deffd 45 | 46 | # 0 -> function to execute before bind ({ ==socket ... }) 47 | # 1 -> port 48 | # 0 <- listening socket fd 49 | { =*opts # ==port 50 | 0 <=un32 -01 sockaddrIpv4 51 | +AFINET +SOCKSTREAM +IPPROTOTCP +socket +??io.net.socket -000 ==s 52 | opts 53 | -01 +bind +??io.net.bind -- 54 | s 256 +listen +??io.net.listen -- 55 | s 56 | } _ /listenOptFd deffd 57 | /listenOpt deffd 58 | 59 | # 0 -> port 60 | # 0 <- listening socket fd 61 | { { } listenOptFd } _ /listenFd deffd 62 | /listen deffd 63 | 64 | # 0 -> listening socket fd 65 | # 0 <- newly accepted connection fd 66 | { # ==fd 67 | +accept +??io.net.accept 68 | } /acceptFd deffd 69 | 70 | # 0 -> listening socket fd 71 | # 0 <- newly accepted connection as file 72 | { # ==fd 73 | acceptFd sys .fdToFile 74 | } /accept deffd 75 | > /tcp net .defv 76 | 77 | # vim: syn=elymas 78 | -------------------------------------------------------------------------------- /elymas/lib/net/udp.ey: -------------------------------------------------------------------------------- 1 | # Provide nice ways to do TCP/IP networking 2 | 3 | < 4 | { ==err _ 0 lt { err ?? } rep } "+??" deffd 5 | { ==err ==actions _ 0 lt { actions err ??? } rep } "+???" deffd 6 | 7 | bin .scan "->" via 8 | bin .print "<-" via 9 | bin .produce "<=" via 10 | sys .linux "+" via 11 | 12 | # 0 -> port 13 | # 1 -> host (as network byte ordered string) 14 | # 0 <- string representing the sockaddr_in 15 | { ==port ==host 16 | +AFINET <=u16 17 | port <-un16 18 | host cat 19 | 0 <-un64 20 | } /sockaddrIpv4 deffd 21 | 22 | # 0 -> "host:port" 23 | # 0 <- connected socket fd 24 | { "^([^:]+):(\\d+)$" regex not { "host:port expected" die } rep 25 | net .dns .resolveIpv4 26 | -01 txt .consume .u16 27 | sockaddrIpv4 28 | +socket _ ==s 29 | -01 +connect +??io.net.connect -- 30 | } /connectFd deffd 31 | 32 | # 0 -> "host:port" 33 | # 0 <- connected socket as file 34 | { 35 | connectFd sys .RDWR 0 sys .fdToFile 36 | } /connect deffd 37 | > /udp net .defv 38 | 39 | # vim: syn=elymas 40 | -------------------------------------------------------------------------------- /elymas/lib/sort.ey: -------------------------------------------------------------------------------- 1 | { /cmp deff _ /a deff dom /d deff 2 | { ==e ==s 3 | s e eq { [ s d ] }' { 4 | s e add 2 div ==m 5 | s m mergeSort =*x 0 ==i 6 | m 1 add e mergeSort =*y 0 ==j 7 | { i _ x -01 1 add =i }' ==l 8 | { j _ y -01 1 add =j }' ==r 9 | [ 10 | { i |x len lt j |y len lt and }' { 11 | i x a j y a cmp l r ? * 12 | }' loop 13 | { i |x len lt }' l loop 14 | { j |y len lt }' r loop 15 | ] 16 | } ? * 17 | } /mergeSort deffst 18 | |a len { 19 | 0 |d len 1 sub mergeSort 20 | } { [ ] } ? * 21 | } /order deffd 22 | 23 | { _ |lt order -01 { * }_ [ 0 ] [ 0 ] '' * } /sort deffd 24 | 25 | # vim: syn=elymas 26 | -------------------------------------------------------------------------------- /elymas/lib/sys.ey: -------------------------------------------------------------------------------- 1 | # abstract system layer 2 | 3 | < 4 | sys .linux "+" via 5 | 6 | { # ==directory 7 | "\0" cat 511 +mkdir 0 neq { ??io.dir.mk } rep 8 | } /mkdir sys .deff 9 | 10 | { # ==directory 11 | "\0" cat +ORDONLY +ODIRECTORY bor 0 +open ==fd 12 | fd 0 lt { ??io.dir.ls.open } { 13 | [ [ { fd +getdents64 _ 0 lt { ??io.dir.ls.getdents } rep } { _ len dearray } loop ] { .dname } each ] 14 | fd +close 0 lt { ??io.dir.ls.close } rep 15 | } ? * 16 | } /readdir sys .deff 17 | 18 | { # ==directory 19 | sys .readdir { 0 -01 * 0 "." * neq } grep 20 | } /ls sys .deff 21 | 22 | { _ ==pattern 0 ==prefixWithDir 23 | "^(.*)/([^/]*)$" regex { 24 | ==dir =pattern 25 | 1 =prefixWithDir 26 | }" { 27 | "." ==dir 28 | }" ? * 29 | [ pattern { ==c 30 | [ 31 | # FIXME: [, ] escapes in regexes 32 | { c 0 "." * eq } { "\\." { } each } 33 | { c 0 "*" * eq } { ".*" { } each } 34 | { c 0 "?" * eq } { "." { } each } 35 | { 1 } { c } 36 | ] conds 37 | } each ] str .fromArray "^" -01 cat "$" cat ==rx 38 | dir sys .readdir { rx regex } grep 39 | prefixWithDir { 40 | { dir "/" cat -01 cat } '*0.0 41 | } rep 42 | } /glob sys .deff 43 | 44 | { 45 | "\0" cat -01 "\0" cat -01 +rename 0 neq { ??io.rename } rep 46 | } /rename sys .deff 47 | 48 | # 0 -> an array of strings determining argv 49 | # 1 -> path to executable 50 | { 51 | -01 "\0" cat -01 [ ] +execve ??proc.exec 52 | } /exec sys .deff 53 | 54 | # 0 -> a shell command 55 | { ==cmd 56 | "/bin/sh\0" [ "sh" "-c" cmd ] "\0" |cat '*00.0 [ ] +execve ??proc.exec 57 | } /shell sys .deff 58 | 59 | # 0 -> function to execute in the child 60 | # 0 <- scope describing child, available members: 61 | # .pid 62 | # .wait (will return some status code) # TODO decompose this according to man 2 waitpid 63 | # .kill 64 | # .in - child stdin 65 | # .out - child stdout 66 | # .err - child stderr (maybe inject some polling on this one per default) 67 | # 68 | # Example: 69 | # { "wget 'http://drahflow.name/' -O -" sys .shell } sys .spawn _ |dump -01 .out .eachLine .wait -- 70 | { =*f 71 | +pipe 0 neq { ??proc.spawn.pipe } rep ==readA ==writeA 72 | +pipe 0 neq { ??proc.spawn.pipe } rep ==readB ==writeB 73 | +pipe 0 neq { ??proc.spawn.pipe } rep ==readC ==writeC 74 | +fork _ ==child not { 75 | [ writeA readB readC 0 1 2 ] { +close } '*0.0 -- 76 | [ readA writeB writeC ] [ 0 1 2 ] { +dup2 } '*00.0 -- 77 | f 0 sys .exit 78 | } rep 79 | child 1 neg eq { ??proc.spawn.fork } { 80 | readA +close { ??proc.spawn.close } rep 81 | writeB +close { ??proc.spawn.close } rep 82 | writeC +close { ??proc.spawn.close } rep 83 | child < ==pid 84 | { pid 0 +waitpid -- } =*wait 85 | { pid -01 +kill -- } =*kill 86 | writeA _ ==inFd sys .fdToFile _ .writeonly ==in 87 | readB _ ==outFd sys .fdToFile _ .readonly ==out 88 | readC _ ==errFd sys .fdToFile _ .readonly ==err 89 | > 90 | } ? * 91 | } /spawn sys .deff 92 | > -- 93 | 94 | # vim: syn=elymas 95 | -------------------------------------------------------------------------------- /elymas/lib/sys/asmroutines.ey: -------------------------------------------------------------------------------- 1 | # assembly-optimized routines for various use cases 2 | 3 | < 4 | sys .asm "::" via 5 | sys .asm .ops ":" via 6 | sys .asm .ops .|label "@" deff 7 | sys .asm .|peek =*:peek 8 | sys .asm .|poke =*:poke 9 | 10 | { :labelRecord [ } "[[" deff 11 | { ] :labelResolve } "]]" deff 12 | 13 | 14 | # concatenate an array full of strings into one, i.e. { |cat fold }" 15 | # 0 -> array of strings 16 | # 0 <- string obtained by concatenating all strings from the array 17 | [[ 18 | /rbx :popqReg 19 | 20 | # sum individual lengths 21 | 0 /rsp /rax :movqMemDisp8Reg 22 | /rax /esi :movlMemReg 23 | /rax /rsi :addqRegReg 24 | 25 | /rdi /rdi :xorqRegReg 26 | 8 /rsi :subqImm8Reg 27 | @countLoop 28 | /rsi /rdx :movqMemReg 29 | 16 /rdx /rdi :addqMemDisp8Reg 30 | 8 /rsi :subqImm8Reg 31 | /rsi /rax :cmpqRegReg 32 | /countLoop :jnzLbl8 33 | 34 | ::internalAllocateString /rax :movqImmReg 35 | /rax :callqReg 36 | 37 | /rdx :popqReg # pop source array 38 | /rax :pushqReg # push target string 39 | 40 | 24 /rax /rdi :leaqMemDisp8Reg 41 | /rdx /eax :movlMemReg 42 | /rdx /rax :addqRegReg 43 | 44 | 8 /rdx :addqImm8Reg 45 | @copyLoop 46 | /rdx /rsi :movqMemReg 47 | 16 /rsi /rcx :movqMemDisp8Reg 48 | 24 /rsi :addqImm8Reg 49 | :reprcx :movsb 50 | 51 | 8 /rdx :addqImm8Reg 52 | /rdx /rax :cmpqRegReg 53 | /copyLoop :jnzLbl8 54 | 55 | /rbx :pushqReg 56 | :retn 57 | ]] [ ] ::createFunction /catstrarray deffd 58 | 59 | # concatenate strings from topmost array marker to top of stack 60 | # into one, i.e. { ] |cat fold }" 61 | # n -> array start marker 62 | # 0... -> strings on the stack 63 | # 0 <- string obtained by concatenating all strings 64 | [[ 65 | /rbx :popqReg 66 | 67 | /rsp /rdx :movqRegReg 68 | 69 | # sum individual lengths 70 | /rdi /rdi :xorqRegReg 71 | /rdx /rsi :movqMemReg 72 | 1 /rsi :cmpqImm8Reg 73 | /nothingToCount :jzLbl8 74 | 75 | @countLoop 76 | 16 /rsi /rdi :addqMemDisp8Reg 77 | 8 /rdx :addqImm8Reg 78 | /rdx /rsi :movqMemReg 79 | 1 /rsi :cmpqImm8Reg 80 | /countLoop :jnzLbl8 81 | 82 | @nothingToCount 83 | # rdi == total number of characters 84 | # rdx == pointer to array start marker 85 | /rdx :pushqReg 86 | 87 | ::internalAllocateString /rax :movqImmReg 88 | /rax :callqReg 89 | # rax == target string of correct length 90 | 91 | /rdx :popqReg 92 | /rdx /rbp :movqRegReg # rbp == pointer to array start marker 93 | 24 /rax /rdi :leaqMemDisp8Reg 94 | 95 | /rdx /rsp :cmpqRegReg 96 | /nothingToCopy :jzLbl8 97 | 98 | @copyLoop 99 | 8 /rdx :subqImm8Reg 100 | /rdx /rsi :movqMemReg 101 | 16 /rsi /rcx :movqMemDisp8Reg 102 | 24 /rsi :addqImm8Reg 103 | :reprcx :movsb 104 | /rdx /rsp :cmpqRegReg 105 | /copyLoop :jnzLbl8 106 | 107 | @nothingToCopy 108 | /rax 0 /rbp :movqRegMemDisp8 # save new string 109 | /rbp /rsp :movqRegReg # drop string fragments from stack 110 | 111 | /rbx :pushqReg 112 | :retn 113 | ]] [ ] ::createFunction /assemblestr deffd 114 | > /asmroutines sys .defv 115 | 116 | # vim: syn=elymas 117 | -------------------------------------------------------------------------------- /elymas/lib/tree.ey: -------------------------------------------------------------------------------- 1 | < 2 | < > _ ==:NONE sys .asm .rawAddress ==:NONEADDR 3 | { sys .asm .rawAddress NONEADDR eq } /isNone deffd 4 | { -01 .set } "=." deffd 5 | 6 | { [ 0 ] } _ "#in" deffd "#out" deffd 7 | 8 | { dom < =*keys 0 ==i { i 1 add =i } =*step > } "#istart" defmd 9 | { _ .i -01 .keys } "#itrans" deffd 10 | { _ .i -01 .|keys len lt not } "#iend" deffd 11 | { _ .step } "#istep" deffd 12 | 13 | { ==k =*get # ==keyGreater ==keySmaller ==keyEquals ==noNode 14 | [ 15 | { get isNone } { k get .k eq } { k get .k lt } { k get .k gt } -438271605 16 | { 1 } { "k: " dump k dump "get .k" dump get .k dump "tree key domain broken, key neither smaller, larger nor equal" die } 17 | ] conds 18 | } /treeconds deffd 19 | 20 | { ==k ==v =*get =*set 21 | { v k node set 0 } 22 | { v get =.v 0 } 23 | { get .L v k insertAndSplay 4 mul 1 add |set |get splayPath } 24 | { get .R v k insertAndSplay 4 mul 2 add |set |get splayPath } 25 | |get k treeconds 26 | } /insertAndSplay deffd 27 | 28 | { ==k =*get =*set 29 | { NONE 1 neg } 30 | { get .v 0 } 31 | { get .L k findAndSplay 4 mul 1 add |set |get splayPath } 32 | { get .R k findAndSplay 4 mul 2 add |set |get splayPath } 33 | |get k treeconds 34 | } /findAndSplay deffd 35 | 36 | { =*get =*set ==path 37 | [ 38 | { path 0 lt } { 1 neg } 39 | { path 5 eq } { |set |get -1010 right right 0 } 40 | { path 6 eq } { get .R right |set |get left 0 } 41 | { path 9 eq } { get .L left |set |get right 0 } 42 | { path 10 eq } { |set |get -1010 left left 0 } 43 | { 1 } { path } 44 | ] conds 45 | } /splayPath deffd 46 | 47 | { =*f ==n n isNone not { n .l |f eachNode n f n .r |f eachNode } rep } /eachNode deffd 48 | 49 | { ==t [ t .root { .k } eachNode ] } "#dom" defmd 50 | { ==t =*f t .root { .v f } eachNode } "#each" defmd 51 | 52 | { .ROOT -1032 insertAndSplay -- } "#=[]" defmd 53 | 54 | { ==tree # ==k 55 | tree .ROOT -102 findAndSplay ==path # ==v (returned) 56 | [ 57 | { path 0 eq } { 1 } 58 | { path 1 eq } { tree .ROOT right 1 } 59 | { path 2 eq } { tree .ROOT left 1 } 60 | { 1 } { -- 0 } 61 | ] conds 62 | } /fetch deffd 63 | 64 | { fetch not { "unknown key requested" die } rep } "#*" defmd 65 | { fetch _ { -- -- 1 } rep } /has defmd 66 | 67 | { ==indent ==n 68 | n isNone { 69 | "" indent { " " cat } rep sys .err .writeall 70 | "" dump 71 | } { 72 | "" indent { " " cat } rep "k: " cat sys .err .writeall n .k dump 73 | "" indent { " " cat } rep "v: " cat sys .err .writeall n .v dump 74 | n .l indent 2 add dumpIndented 75 | n .r indent 2 add dumpIndented 76 | } ? * 77 | } /dumpIndented deffd 78 | 79 | { < ==k ==v NONE _ ==l ==r { = } =*set > } /node deffd 80 | 81 | { _ { =.root }_ -01 { .root }_ } /ROOT defmd 82 | { _ { =.l }_ -01 { .l }_ } /L defmd 83 | { _ { =.r }_ -01 { .r }_ } /R defmd 84 | 85 | { * _ .R * _ .L -0*3*41*25* } /left deffd 86 | { * _ .L * _ .R -0*3*41*25* } /right deffd 87 | 88 | { ==t tree ==n t dom { ==k k t * k n =[] } each n } /clone defmd 89 | 90 | < 91 | { .root 0 dumpIndented } /dump defmd 92 | 93 | { < { = } =*set NONE ==root > } 94 | > -- _ "#iclone" deffd 95 | > -- /tree deffd 96 | 97 | # longer versions of L+R 98 | 99 | # { =*get =*set 100 | # get ==p 101 | # p .r ==x 102 | # x .l p =.r 103 | # p x =.l 104 | # x set 105 | # } /left deffd 106 | # 107 | # { # =*get =*set 108 | # * _ .R * _ .L 109 | # # p { p =.r } x { x =.l } { x .l } 110 | # -0*3*41*25* 111 | # } /left deffd 112 | 113 | # { =*get =*set 114 | # get ==p 115 | # p .l ==x 116 | # x .r p =.l 117 | # p x =.r 118 | # x set 119 | # } /right deffd 120 | 121 | # { # =*get =*set 122 | # * _ .L * _ .R 123 | # # p { p =.l } x { x =.r } { x .r } 124 | # -0*3*41*25* 125 | # } /right deffd 126 | 127 | # vim: syn=elymas 128 | -------------------------------------------------------------------------------- /elymas/lib/txt.ey: -------------------------------------------------------------------------------- 1 | < 2 | < 3 | # 0 -> string 4 | # 0 <- leading digits converted to int (0, if none) 5 | { "^(\\d*)" regex -- ==n 6 | [ n { 48 sub } each ] reverse 10 math .unbase 7 | } [ 0 ] [ 0 ] '' /u deffd 8 | 9 | # 0 -> string 10 | # 0 <- leading hexadecimal digits converted to int (0, if none) 11 | [ 12 | 0 1 2 3 4 5 6 7 8 9 13 | 7 { 0 } rep 14 | 10 11 12 13 14 15 15 | 26 { 0 } rep 16 | 10 11 12 13 14 15 17 | ] =*:hexDigitsReverse 18 | 19 | { "^([0-9A-Fa-f]*)" regex -- ==n 20 | [ n { 48 sub hexDigitsReverse } each ] reverse 16 math .unbase 21 | } [ 0 ] [ 0 ] '' /hu deffd 22 | > /consume defvd 23 | 24 | < 25 | # 0 -> positive integer (or zero) 26 | # 0 <- decimal representation as string 27 | { 28 | _ { [ -01 10 math .base reverse "0123456789" each ] str .fromArray } { -- "0" } ? * 29 | } [ 0 ] [ 0 ] '' /u deffd 30 | 31 | # 0 -> positive integer (or zero) 32 | # 0 <- hexadecimal representation as string 33 | { 34 | _ { [ -01 16 math .base reverse "0123456789ABCDEF" each ] str .fromArray } { -- "0" } ? * 35 | } [ 0 ] [ 0 ] '' /hu deffd 36 | 37 | # 0 -> integer 38 | # 0 <- decimal representation as string 39 | { 40 | _ 0 lt { neg u "-" -01 cat } |u ? * 41 | } [ 0 ] [ 0 ] '' /i deffd 42 | > /produce defvd 43 | > /txt defvd 44 | 45 | # vim: syn=elymas 46 | -------------------------------------------------------------------------------- /elymas/lib/utf8.ey: -------------------------------------------------------------------------------- 1 | < 2 | < 3 | txt .consume .|hu "%" defq 4 | { "2120" "-" | |le "021" "-" | |ge |and } /in defq 5 | sys .asm .|rawAddress =*:addr 6 | 7 | { [ -01 ] cat }" =*:emit 8 | { 0 ==accum one =*next }' =*:init 9 | 10 | { { accum emit one =next }' -01 reverse 11 | { =*p =*n { { 12 | p { %3F band accum %40 mul add =accum n }' 13 | { < { ==c [ %FFFD ] cat init c next }' =*replace > ???enc.utf8.ill-formed }' ? * 14 | }' =next }' } each 15 | } /trail deffd 16 | 17 | [ # compare Table 3-7 of http://www.unicode.org/versions/Unicode6.3.0/ch03.pdf 18 | { _ %7F le }" |emit 19 | { _ %C2 %DF in }" { %1F band =accum }' [ { _ %80 %BF in }" ] trail ; 20 | { _ %E0 eq }" { %0F band =accum }' [ { _ %A0 %BF in }" { _ %80 %BF in }" ] trail ; 21 | { _ %E1 %EC in }" { %0F band =accum }' [ { _ %80 %BF in }" _ ] trail ; 22 | { _ %ED eq }" { %0F band =accum }' [ { _ %80 %9F in }" { _ %80 %BF in }" ] trail ; 23 | { _ %EE %EF in }" { %0F band =accum }' [ { _ %80 %BF in }" _ ] trail ; 24 | { _ %F0 eq }" { %07 band =accum }' [ { _ %90 %BF in }" { _ %80 %BF in }" _ ] trail ; 25 | { _ %F1 %F3 in }" { %07 band =accum }' [ { _ %80 %BF in }" _ _ ] trail ; 26 | { _ %F4 eq }" { %07 band =accum }' [ { _ %80 %8F in }" { _ %80 %BF in }" _ ] trail ; 27 | { -- 1 }" { < { [ %FFFD ] cat init }' =*replace > ???enc.utf8.ill-formed } 28 | ] ==:C { C conds } ==:one 29 | 30 | # convert string to sequence of UTF8 codepoints 31 | # 0 -> input string 32 | # 0 <- the code points represented by that string 33 | { init [ ] -01 { next } each 34 | one addr |next addr neq { < { [ %FFFD ] cat }' =*replace > ???enc.utf8.ill-formed } rep 35 | } 36 | > -- /consume deffd 37 | > /utf8 defvd 38 | 39 | # vim: syn=elymas 40 | -------------------------------------------------------------------------------- /elymas/lib/util.ey: -------------------------------------------------------------------------------- 1 | { ==spec 2 | [ spec { ==c 3 | [ 4 | { c 48 ge c 57 le and }' { c 48 sub } 5 | { c 46 eq }' { ] [ } 6 | { 1 }' { "invalid ' spec: " spec cat die } 7 | ] conds 8 | } each ] '' 9 | } "'" deffd 10 | 11 | "'" | "*" | ; "'*" deffd 12 | 13 | # vim: syn=elymas 14 | -------------------------------------------------------------------------------- /elymas/lib/wrapper.ey: -------------------------------------------------------------------------------- 1 | { ==v ==source 2 | < 3 | /has source keys eq any { 4 | { /d defvs d source .has { d source * } { v } ? * } 5 | } { 6 | { /d defvs d source dom eq any { d source * } { v } ? * } 7 | } ? * "#*" deffst 8 | { source -01 . } "#." deffst # TODO: think about instantiating all keys explicitely 9 | { source -01 .| } "#.|" deffst 10 | { source -01 .? } "#.?" deffst 11 | > 12 | } /default deffd 13 | 14 | # vim: syn=elymas 15 | -------------------------------------------------------------------------------- /elymas/lib/xml.ey: -------------------------------------------------------------------------------- 1 | < 2 | < 3 | txt .consume .|hu "%" defq 4 | { "2120" "-" | |le "021" "-" | |ge |and } /in defq 5 | map ==defaultEnts [ { "&" /amp } { "<" /lt } { ">" /gt } { "'" /apos } { "\"" /quot } ] { * defaultEnts =[] } each 6 | { "Unconfigured npeek/take/get/set/noErr/snip" die } -000000 =*npeek =*take =*get =*set =*noErr =*snip 7 | { 0 npeek } =*peek map ==ents 8 | 9 | # parser generator 10 | { _ sys .typed .type 1 eq { ==str { 1 ==r str { peek eq r and =r take } each r _ |noErr rep } } { } ? * } /lit deffd 11 | { lit =*p { get ==s [ p { ] _ len dearray } { ] -- s set } ? * 1 } } ",?" deffd 12 | { lit =*p { get ==s { get =s [ p } { ] _ len dearray } loop ] -- s set 1 } } ",*" deffd 13 | { _ ,* ,; } ",+" deffd 14 | { lit =*q lit =*p { get ==s [ p { ] _ len dearray 1 } { ] -- s set q } ? * } } ",|" deffd 15 | { lit ==q lit =*p { p q { 0 } ? * } } ",;" deffd 16 | { [ [ } { ] |lit each ] ",;" | fold } -01 ",[" deffd ",]" deffd 17 | { defvst }' =*:defp 18 | # FIXME: remove the useless { * }_ once static / typed are correctly discerned by optimizations 19 | { ==name "}" | * { ,[ } -01 ; { ,] } ; { * { * }_ _ name defp * }_ name defp } "}==" defq 20 | "{" | "(" defq { 1 "}" | * } ")" defq 21 | 22 | { lit =*p lit =*q { get ==s 23 | { get =s [ p { ] -- s set [ 0 } { ] -- s set [ q } ? * } { ] _ len dearray } loop ] -- s set 1 24 | } } /upto deffd 25 | { txt .consume .hu ==h ==l { peek take l h in } } "-%" defq 26 | 27 | # compare http://www.w3.org/TR/2006/REC-xml11-20060816/ 28 | { peek take _ %41 %5A in -01 %61 %7A in or } "[A-Za-z]" == 29 | { peek take ==c c %30 %39 in } "[0-9]" == 30 | { peek take ==c c %3C neq c %26 neq and } "[^<&]" == 31 | { peek take ==c c %41 %46 in c %61 %66 in or c %30 %39 in or } "[0-9a-fA-F]" == 32 | { peek take ==c c %3C neq c %26 neq and c %22 neq and } "[^<&\"]" == 33 | { peek take ==c c %3C neq c %26 neq and c %27 neq and } "[^<&']" == 34 | { peek take ==c c %41 %5A in c %61 %7A in or c %30 %39 in or 35 | c %2E eq or c %5F eq or c %2D eq or } "[A-Za-z0-9._-]" == 36 | { peek take ==c c %20 eq c %D eq or c %A eq or c %3F %5A in or c %61 %7A in or c %21 eq or 37 | c %23 %25 in or c %27 %3B in or c %3D eq or c %5F eq or } ==PubidChar 38 | { peek take ==c c %1 %2C in c %2E %D7FF in or c %E000 %FFFD in or c %10000 %10FFFF in or } ==CharNotMinus 39 | { peek take ==c c %1 %D7FF in c %E000 %FFFD in or c %10000 %10FFFF in or } ==Char 40 | [ ":" "_" %41 -%5A %61 -%7A %C0 -%D6 %D8 -%F6 %F8 -%2FF %370 -%37D 41 | %37F -%1FFF %200C -%200D %2070 -%218F %2C00 -%2FEF %3001 -%D7FF %F900 -%FDCF %FDF0 -%FFFD 42 | %10000 -%EFFFF ] ",|" | fold ==NameStartChar 43 | [ NameStartChar "-" "." %30 -%39 %B7 -%B7 %0300 -%036F %203F -%2040 ] ",|" | fold ==NameChar 44 | { { peek [ %20 %9 %D %A ] eq any take } ,+ }==S 45 | 46 | { "" upto "]]>" }==CDSect 47 | { ( get ) "[^<&]" | "]]>" upto ( get snip text ) }==CharData 48 | { CharData ,? ,[ [ element Reference CDSect PI Comment ] ",|" | fold CharData ,? ,] ,* }==content 49 | { ,[ "&#" ( get ) "[0-9]" | ,+ ( get snip txt .consume .u [ -01 ] str .fromArray text ) ";" ,] 50 | ,[ "&#x" ( get ) "[0-9a-fA-F]" | ,+ ( get snip txt .consume .hu [ -01 ] str .fromArray text ) ";" ,] ,| }==CharRef 51 | { "&" ( get ) Name ( get snip ) ";" ( _ ents .has { ents * text } { ??parse.xml.undeclared-entity } ? * ) }==EntityRef 52 | { EntityRef CharRef ,| }==Reference 53 | { ,[ "\"" ( get ) "[^<&\"]" | Reference ,| ,* ( get snip ) "\"" ,] 54 | ,[ "'" ( get ) "[^<&']" | Reference ,| ,* ( get snip ) "'" ,] ,| }==AttValue 55 | { ( get ) Name ( get snip ) Eq AttValue }==Attribute 56 | { "<" ( get ) Name ( get snip [ ) ,[ S Attribute ,] ,* ( ] elem ) S ,? "/>" }==EmptyElemTag # TODO: left-factorize 57 | { "<" ( get ) Name ( get snip [ ) ,[ S Attribute ,] ,* ( ] elem ) S ,? ">" }==STag 58 | { "" }==ETag 59 | { ,[ "\"" PubidChar ,* "\"" ,] ,[ "'" PubidChar "'" upto "'" ,] ,| }==PubidLiteral 60 | { ,[ "\"" { take 1 } "\"" upto "\"" ,] ,[ "'" { take 1 } "'" upto "'" ,] ,| }==SystemLiteral 61 | { markupdecl DeclSep ,| ,* }==intSubset 62 | { ,[ "SYSTEM" S SystemLiteral ,] ,[ "PUBLIC" S PubidLiteral S SystemLiteral ,] ,| }==ExternalID 63 | { NameStartChar NameChar ,* }==Name 64 | { Name }==PITarget # TODO: guard against [Xx][Mm][Ll] 65 | { "" }==Comment 66 | { "" upto ,] ,? "?>" }==PI 67 | { Comment PI ,| S ,| }==Misc 68 | { S ,? "=" S ,? }==Eq 69 | { "1.1" }==VersionNum 70 | { "[A-Za-z]" | "[A-Za-z0-9._-]" | ,* }==EncName 71 | { S "encoding" Eq ,[ "\"" EncName "\"" ,] ,[ "'" EncName "'" ,] ,| }==EncodingDecl 72 | { S "version" Eq ,[ "'" VersionNum "'" ,] ,[ "\"" VersionNum "\"" ,] ,| }==VersionInfo 73 | { "" }==XMLDecl 74 | { "" }==doctypedecl 75 | { XMLDecl Misc ,* doctypedecl ,? Misc ,* }==prolog 76 | { S "standalone" Eq ,[ "'" "yes" "no" ,| "'" ,] ,[ "\"" "yes" "no" ,| "\"" ,] ,| }==SDDecl 77 | { EmptyElemTag ,[ STag ( [ ) content ( ] -101 .setChildren ) ETag ,] ,| }==element 78 | { prolog element Misc ,* }==document 79 | 80 | { _ =*s len ==LEN 0 ==i 0 ==last 81 | { i add LEN lt { i s } { 1 neg } ? * } =npeek { i 1 add =i } =take { i } =get { =i } =set { i =last } =noErr 82 | { |s str .infix } =snip defaultEnts .clone =ents 83 | { document * { i LEN neq { ??parse.xml.trailing-garbage } rep } { ??parse.xml } ? * } 84 | { -- < last |s str .postfix ==remaining > ??!' } ?!parse.xml 85 | } 86 | 87 | { < "" ==name ==text > } /text deffd 88 | { < -01 ==name 89 | map ==attr _ len _ ==l dearray l 2 div { -01 attr =[] } rep 90 | [ ] ==children { =children } =*setChildren 91 | > } /elem deffd 92 | > -- /parse deffd 93 | > /xml defvd 94 | 95 | # vim: syn=elymas 96 | -------------------------------------------------------------------------------- /elymas/loaded.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | [ 4 | "lib/util.ey" 5 | "lib/err.ey" 6 | "lib/bin.ey" 7 | "lib/sys/asmroutines.ey" 8 | sys .?linux { "lib/sys/linux.ey" } rep 9 | sys .?linux { # FIXME: port these to other architectures one day 10 | "lib/sys.ey" 11 | "lib/net.ey" 12 | "lib/net/tcp.ey" 13 | "lib/net/udp.ey" 14 | "lib/net/dns.ey" 15 | "lib/net/alg.ey" 16 | "lib/net/alg/server.ey" 17 | "lib/net/alg/http.ey" 18 | "lib/net/alg/uri.ey" 19 | } rep 20 | "lib/list.ey" 21 | "lib/map.ey" 22 | "lib/tree.ey" 23 | "lib/wrapper.ey" 24 | "lib/sort.ey" 25 | "lib/crypt.ey" 26 | "lib/parser.ey" 27 | ] { _ dump include }' each 28 | 29 | { 30 | sys .argv len { 0 sys .argv * } { "/dev/stdin" } ? * include 31 | 0 sys .exit 32 | }' "loaded" sys .freeze 33 | -------------------------------------------------------------------------------- /elymas/memdump.ey: -------------------------------------------------------------------------------- 1 | txt .consume .|hu "%" defq 2 | 3 | %400000000000 ==:MARKBASE 4 | %500000000000 ==:BLOCKBASE 5 | %600000000000 ==:HEAPBASE 6 | %100000000000 ==:ELFBASE 7 | 8 | < 9 | sys .asm .ops ":" via 10 | sys .asm "::" via 11 | 12 | [ # ==addr 13 | 8 /r15 :subqImm8Reg 14 | /r15 :popqMem 15 | 16 | /rax :popqReg 17 | 8 /rax /rax :movqMemDisp8Reg # this should be a boxed integer 18 | /rax :pushqMem # load data to stack 19 | ::internalAllocateInteger /rax :movqImmReg 20 | /rax :callqReg 21 | 8 /rax :popqMemDisp8 # store data to integer object 22 | /rax :pushqReg 23 | 24 | /r15 :pushqMem 25 | 8 /r15 :addqImm8Reg 26 | :retn 27 | ] [ ] sys .asm .createFunction 28 | > -- /peek64 deffd 29 | 30 | sys .linux "+" via 31 | 32 | < 33 | "shared\0" +ORDONLY 0 +open ==fd 34 | fd +fstat -- # TODO: handle errors 35 | .size ==s 36 | ELFBASE s +PROTREAD +MAPPRIVATE fd 0 +mmap ELFBASE eq assert 37 | > -- 38 | 39 | ELFBASE 32 add peek64 _ dump ==phdr 40 | ELFBASE 56 add peek64 65536 mod _ dump ==phdrCount 41 | 42 | [ 43 | phdrCount { 44 | ELFBASE phdr add peek64 %100000000 mod 1 eq { # LOAD program header 45 | < 46 | ELFBASE phdr add 8 add peek64 ==fileStart 47 | ELFBASE phdr add 16 add peek64 ==memoryStart 48 | ELFBASE phdr add 32 add peek64 memoryStart add ==memoryEnd 49 | > 50 | } rep 51 | phdr %38 add =phdr 52 | } rep 53 | ] _ ==memoryLayout 54 | 55 | { =*f _ =*a len ==maxI 0 ==i 56 | { 57 | i maxI lt { i a f } { 0 } ? * 58 | } { i 1 add =i } loop 59 | } /eachWhile deffd 60 | 61 | { ==addr 62 | memoryLayout { ==m 63 | [ 64 | { addr m .memoryStart lt } { 1 } 65 | { addr m .memoryEnd ge } { 1 } 66 | { 1 } { 67 | addr m .memoryStart sub m .fileStart add ELFBASE add peek64 68 | 0 # loop done 69 | } 70 | ] conds 71 | } eachWhile 72 | } /peekElf64 deffst 73 | 74 | HEAPBASE peekElf64 %FFFFFFFFFFFF0000 band %9E00000000000000 eq assert 75 | 76 | sys .asm .|programStart sys .asm .rawCodeAddress { add peekElf64 }_ =*peekProgramStart 77 | 2 peekProgramStart _ dump ==initialRsp 78 | 12 peekProgramStart _ dump ==initialR15 79 | 32 peekProgramStart HEAPBASE add _ dump ==HEAPEND 80 | 78 peekProgramStart _ dump ==initialR14 81 | 82 | < 83 | HEAPEND HEAPBASE sub 16 div 8 div str .alloc _ str .zero ==objectSeen 84 | { 85 | HEAPBASE sub 16 div _ objectSeen str .bitTest -01 86 | objectSeen str .bitSet 87 | } 88 | > -- /seen deffst 89 | 90 | 91 | 1 neg ==indent 92 | { ==addr ==header 93 | indent { " " sys .out .writeall } rep 94 | header sys .out .writeall 95 | " " sys .out .writeall 96 | addr txt .produce .hu sys .out .writeall 97 | "\n" sys .out .writeall 98 | } /out deffst 99 | 100 | { ==addr ==header ==type 101 | indent { " " sys .out .writeall } rep 102 | header sys .out .writeall 103 | " " sys .out .writeall 104 | addr txt .produce .hu sys .out .writeall 105 | " " sys .out .writeall 106 | type sys .out .writeall 107 | "\n" sys .out .writeall 108 | } /out2 deffst 109 | 110 | { ==addr 111 | indent 1 add =indent 112 | [ 113 | { addr HEAPBASE lt } { "-----" addr out } 114 | { addr HEAPEND ge } { "----" addr out } 115 | { addr seen } { "----" addr out } 116 | { 1 } { 117 | { "----------" addr out2 } ":" deffst 118 | addr peekElf64 %1000000000000000 div 119 | [ 120 | { :integer } 121 | { :string 122 | addr 16 add peekElf64 "len:" -01 out 123 | addr 24 add peekElf64 256 math .base str .fromArray 0 out 124 | } 125 | { :errornous_2 } 126 | { :errornous_3 } 127 | { :extension_area 128 | addr peekElf64 %00000000FFFFFFFF band _ "len:" -01 out 8 div 1 -01 range { 129 | 8 mul addr add peekElf64 dumpElf 130 | } each 131 | } 132 | { :function 133 | addr 8 add peekElf64 dumpElf 134 | addr 16 add peekElf64 dumpElf 135 | addr 24 add peekElf64 dumpElf 136 | } 137 | { :function_code 138 | addr 16 add peekElf64 %FFFF band %B848 eq 139 | addr 26 add peekElf64 %FFFF band %E0FF eq and 140 | { 141 | addr 18 add peekElf64 16 sub dumpElf 142 | } { 143 | addr 8 add peekElf64 _ "oplen:" -01 out ==oplen 144 | addr peekElf64 %00000000FFFFFFFF band _ "len:" -01 out 8 div 2 oplen 8 div add -01 range { 145 | 8 mul addr add peekElf64 dumpElf 146 | } each 147 | } ? * 148 | } 149 | { :array 150 | addr peekElf64 %00000000FFFFFFFF band _ "len:" -01 out 8 div 1 -01 range { 151 | 8 mul addr add peekElf64 dumpElf 152 | } each 153 | } 154 | { :function_type 155 | addr peekElf64 %00000000FFFFFFFF band _ "len:" -01 out 8 div 1 -01 range { 156 | 8 mul addr add peekElf64 dumpElf 157 | } each 158 | } 159 | # more physical scope dumping, but harder to follow output 160 | # { :scope 161 | # addr peekElf64 %00000000FFFFFFFF band _ "len:" -01 out 8 div 1 -01 range { 162 | # 8 mul addr add peekElf64 dumpElf 163 | # } each 164 | # } 165 | { :scope 166 | addr 8 add peekElf64 ==nameTable 167 | nameTable { nameTable 8 add peekElf64 %00000000FFFFFFFF band 16 div 1 sub } { 0 } ? * ==nameTableFill 168 | 169 | { ==i 170 | i nameTableFill lt { 171 | i 1 add 16 mul nameTable add peekElf64 ==name 172 | name 24 add peekElf64 256 math .base str .fromArray 0 out 173 | } rep 174 | } /dumpLocalName deffst 175 | 176 | addr peekElf64 %00000000FFFFFFFF band 8 div _ ==scopeLen 4 -01 range { 177 | _ 4 sub dumpLocalName 178 | 8 mul addr add peekElf64 dumpElf 179 | } each 180 | 181 | addr 24 add peekElf64 ==extensionArea 182 | extensionArea { 183 | "" 0 out 184 | extensionArea peekElf64 %00000000FFFFFFFF band 8 div 1 -01 range { 185 | _ 1 sub scopeLen add 4 sub dumpLocalName 186 | 8 mul extensionArea add peekElf64 dumpElf 187 | } each 188 | } { } ? * 189 | 190 | "" 0 out 191 | addr 16 add peekElf64 dumpElf 192 | } 193 | { :name_table 194 | addr 8 add peekElf64 _ "fill:" -01 out 16 div 1 -01 range { 195 | 16 mul addr add peekElf64 dumpElf 196 | } each 197 | } 198 | { :errornous_B } 199 | { :errornous_C } 200 | { :errornous_D } 201 | { :errornous_E } 202 | { :errornous_F } 203 | ] * * 204 | } 205 | ] conds 206 | indent 1 sub =indent 207 | } /dumpElf deffst 208 | 209 | "=== From current scope ===\n" sys .out .writeall 210 | initialR14 dumpElf 211 | "=== From current data stack ===\n" sys .out .writeall 212 | { initialRsp %FFFF band } { 213 | initialRsp peekElf64 dumpElf 214 | initialRsp 8 add =initialRsp 215 | } loop 216 | "=== From current call stack ===\n" sys .out .writeall 217 | { initialR15 %FFFF band } { 218 | initialR15 peekElf64 dumpElf 219 | initialR15 8 add =initialRsp 220 | } loop 221 | 222 | # vim: syn=elymas 223 | -------------------------------------------------------------------------------- /elymas/optimized.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | [ 4 | "lib/math.ey" 5 | "lib/txt.ey" 6 | "lib/sys/optroutines.ey" 7 | "lib/sys/opt.ey" 8 | ] { _ dump include }' each 9 | 10 | { 11 | sys .argv len { 0 sys .argv * } { "/dev/stdin" } ? * include 12 | 0 sys .exit 13 | }' "optimized" sys .freeze 14 | -------------------------------------------------------------------------------- /elymas/ptracePerf/perf.ey: -------------------------------------------------------------------------------- 1 | 22948 ==:pid 2 | 3 | { 1 } { 4 | pid sys .linux .ptrace .attach -- 5 | pid 0 sys .linux .waitpid -- 6 | pid sys .linux .ptrace .peekUser .rip -- ==rip 7 | # pid rip sys .linux .ptrace .peek -- ==instr 8 | pid sys .linux .ptrace .detach -- 9 | 10 | rip dump 11 | } loop 12 | 13 | # vim: syn=elymas 14 | -------------------------------------------------------------------------------- /elymas/shared.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | [ 4 | "lib/util.ey" 5 | "lib/err.ey" 6 | "lib/bin.ey" 7 | "lib/sys/asmroutines.ey" 8 | sys .?linux { "lib/sys/linux.ey" } rep 9 | "lib/sys/so.ey" 10 | sys .?linux { # FIXME: port these to other architectures one day 11 | "lib/sys.ey" 12 | "lib/net.ey" 13 | "lib/net/tcp.ey" 14 | "lib/net/udp.ey" 15 | "lib/net/dns.ey" 16 | "lib/net/alg.ey" 17 | "lib/net/alg/server.ey" 18 | "lib/net/alg/http.ey" 19 | "lib/net/alg/uri.ey" 20 | } rep 21 | "lib/list.ey" 22 | "lib/map.ey" 23 | "lib/tree.ey" 24 | "lib/wrapper.ey" 25 | "lib/sort.ey" 26 | "lib/crypt.ey" 27 | "lib/parser.ey" 28 | ] { _ dump include }' each 29 | 30 | { 31 | sys .argv len { 0 sys .argv * } { "/dev/stdin" } ? * include 32 | 0 sys .exit 33 | }' "shared" sys .so .freeze 34 | -------------------------------------------------------------------------------- /elymas/tree.test: -------------------------------------------------------------------------------- 1 | tree ==t 2 | 10 10 t =[] 3 | 5 5 t =[] 4 | 4 4 t =[] 5 | 3 3 t =[] 6 | 2 2 t =[] 7 | 8 | t .dump 9 | t dom dump 10 | 11 | 5 t * dump 12 | 13 | 5 t .has dump 14 | 7 t .has dump 15 | 16 | t .clone .dump 17 | 18 | t { dump } each 19 | 20 | 1 t add .dump 21 | 2 t add .dump 22 | t t mul .dump 23 | 24 | t .dump 25 | 4 t * dump 26 | t .dump 27 | -------------------------------------------------------------------------------- /examples/compiler-missing.sh: -------------------------------------------------------------------------------- 1 | ( cd working; ls *.ey ) | sed -e 's/.ey/.test/' | while read n; do 2 | [ ! -r working-compiler/"$n" ] && echo $n 3 | done 4 | -------------------------------------------------------------------------------- /examples/non-working/cross.ey: -------------------------------------------------------------------------------- 1 | [ 1 2 3 ] [ 1 2 3 ] add dump 2 | -------------------------------------------------------------------------------- /examples/non-working/freeze.ey: -------------------------------------------------------------------------------- 1 | { 2 | "Ohai!" die 3 | } "freeze.bin" sys .freeze 4 | -------------------------------------------------------------------------------- /examples/non-working/scopeweird.ey: -------------------------------------------------------------------------------- 1 | # TODO: make a decision on whether this is good or bad 2 | 3 | { < } /x deff 4 | 5 | |x ">" | |dump -2*1*0* 6 | -------------------------------------------------------------------------------- /examples/regressions/000001.ey: -------------------------------------------------------------------------------- 1 | 0 ==i 2 | 3 | 0 10 range { 4 | [ 5 | { _ 5 lt } { i 1 add =i } 6 | ] conds -- 7 | } each 8 | 9 | i 5 eq not { /wrong die } rep 10 | -------------------------------------------------------------------------------- /examples/working-compiler/abstract-right.test: -------------------------------------------------------------------------------- 1 | ../working/abstract-right.ey -------------------------------------------------------------------------------- /examples/working-compiler/apply.test: -------------------------------------------------------------------------------- 1 | { 2 | quoted { ==name =*f 3 | name "|" sys .executeIdentifier 4 | f 5 | name "=" sys .executeIdentifier 6 | } { ==name =*f name | f name = } ? * 7 | } "|=" defq 8 | 9 | 0 ==i 10 | i dump 11 | { 1 add } |=i 12 | i dump 13 | 14 | { 15 | 0 ==j 16 | { 1 add } |=j 17 | j dump 18 | } * 19 | -------------------------------------------------------------------------------- /examples/working-compiler/array-assign.test: -------------------------------------------------------------------------------- 1 | ../working/array-assign.ey -------------------------------------------------------------------------------- /examples/working-compiler/array-list.test: -------------------------------------------------------------------------------- 1 | ../working/array-list.ey -------------------------------------------------------------------------------- /examples/working-compiler/arraycat.test: -------------------------------------------------------------------------------- 1 | ../working/arraycat.ey -------------------------------------------------------------------------------- /examples/working-compiler/arrays.test: -------------------------------------------------------------------------------- 1 | ../working/arrays.ey -------------------------------------------------------------------------------- /examples/working-compiler/asm.test: -------------------------------------------------------------------------------- 1 | ../working/asm.ey -------------------------------------------------------------------------------- /examples/working-compiler/auto_loop.test: -------------------------------------------------------------------------------- 1 | |not |not add =*f 2 | 0 f dump 3 | 1 f dump 4 | -------------------------------------------------------------------------------- /examples/working-compiler/bor.test: -------------------------------------------------------------------------------- 1 | ../working/bor.ey -------------------------------------------------------------------------------- /examples/working-compiler/cat.test: -------------------------------------------------------------------------------- 1 | ../working/cat.ey -------------------------------------------------------------------------------- /examples/working-compiler/complex-exec.test: -------------------------------------------------------------------------------- 1 | ../working/complex-exec.ey -------------------------------------------------------------------------------- /examples/working-compiler/concat.test: -------------------------------------------------------------------------------- 1 | ../working/concat.ey -------------------------------------------------------------------------------- /examples/working-compiler/coroutine.test: -------------------------------------------------------------------------------- 1 | { ==caller ==data 2 | "coroutine 1" dump data dump 3 | data caller 1 ! =caller =data 4 | "coroutine 2" dump data dump 5 | data caller 1 ! =caller =data 6 | "coroutine 3" dump data dump 7 | data caller 1 ! 8 | } !! ==cr 9 | 10 | "data" 11 | cr 1 ! -- 12 | "here 1" dump 13 | cr 1 ! -- 14 | "here 2" dump 15 | cr 1 ! -- 16 | "here 3" dump 17 | 18 | 0 sys .exit 19 | -------------------------------------------------------------------------------- /examples/working-compiler/coroutine2.test: -------------------------------------------------------------------------------- 1 | 0 ==?cr 2 | 0 ==main 3 | 4 | { =cr 5 | 1 =main 6 | "main routine" dump 7 | } { 8 | ==caller 9 | 0 =main 10 | "coroutine" dump 11 | } !!' 12 | 13 | "afterwards" dump # mind = blown 14 | main { cr 0 ! } rep 15 | -------------------------------------------------------------------------------- /examples/working-compiler/coroutine3.test: -------------------------------------------------------------------------------- 1 | { 2 | { } { -- restart } !!' 3 | } /restart deffd 4 | 5 | 0 ==i 6 | 7 | restart ==checkpoint 8 | 9 | i 1 add =i 10 | i dump 11 | 12 | i 7 lt { checkpoint 0 ! } rep 13 | -------------------------------------------------------------------------------- /examples/working-compiler/coroutine4.test: -------------------------------------------------------------------------------- 1 | { ==caller ==data 2 | "coroutine 1" dump data dump 3 | data caller * =caller =data 4 | "coroutine 2" dump data dump 5 | data caller * =caller =data 6 | "coroutine 3" dump data dump 7 | data caller * 8 | } !! ==cr 9 | 10 | "data" 11 | cr * -- 12 | "here 1" dump 13 | cr * -- 14 | "here 2" dump 15 | cr * -- 16 | "here 3" dump 17 | 18 | 0 sys .exit 19 | -------------------------------------------------------------------------------- /examples/working-compiler/curry-std.test: -------------------------------------------------------------------------------- 1 | 3 3 ||add ||add mul * * dump 2 | ||add ||add mul { ** }_ =*m 3 | 4 | 3 3 m dump # should be 00024 5 | -------------------------------------------------------------------------------- /examples/working-compiler/curry.test: -------------------------------------------------------------------------------- 1 | { _ ==f _ sys .typed .inputs ==inputs 2 | sys .typed .outputs ==outputs 3 | inputs len 2 lt { f } { 4 | { "t from curry should never execute" die } 5 | [ inputs len 1 sub inputs * ] outputs '' ==t 6 | 0 inputs len 2 sub range reverse { ==i t [ i inputs * ] [ t ] '' =t } each 7 | 1 inputs len range reverse { ==i 8 | f < =*g { { g }_ } > -- [ i inputs * ] [ t ] '' =f 9 | 0 t sys .typed .outputs * =t 10 | } each 11 | f 12 | } ? * 13 | } /curry deffd 14 | 15 | |add curry ==a 16 | 5 5 a * * dump 17 | 18 | a sys .typed .inputs dump 19 | a sys .typed .outputs _ dump 0 -01 * ==b 20 | b sys .typed .inputs dump 21 | b sys .typed .outputs _ dump 0 -01 * ==c 22 | 23 | 3 3 |a |a mul * * dump 24 | 25 | # vim: syn=elymas 26 | -------------------------------------------------------------------------------- /examples/working-compiler/deffd.test: -------------------------------------------------------------------------------- 1 | 1 -- 2 | { "here" } /foo deffd 3 | { foo } /bar deffd 4 | { bar } /quux deffd 5 | quux 6 | -- 7 | quux 8 | die 9 | -------------------------------------------------------------------------------- /examples/working-compiler/defvs.test: -------------------------------------------------------------------------------- 1 | { 2 | "herea" /fooa defvs 3 | "hereb" /foob defvs 4 | "herec" /fooc defvs 5 | "hered" /food defvs 6 | "heree" /fooe defvs 7 | "heref" /foof defvs 8 | "hereg" /foog defvs 9 | "hereg" /fooga defvs 10 | "hereg" /foogb defvs 11 | "hereg" /foogc defvs 12 | "hereg" /foogd defvs 13 | "hereg" /fooge defvs 14 | "hereg" /foogf defvs 15 | "hereg" /foogg defvs 16 | "hereg" /foogh defvs 17 | "hereg" /foogi defvs 18 | "hereg" /foogj defvs 19 | "hereh" /fooh defvs 20 | "herei" /fooi defvs 21 | "herej" /fooj defvs 22 | "herek" /fook defvs 23 | "herel" /fool defvs 24 | "herem" /foom defvs 25 | "heren" /foon defvs 26 | "hereo" /fooo defvs 27 | { { foon } } * /bar deffd 28 | { bar } /quux deffd 29 | quux 30 | quux 31 | } * 32 | -- 33 | die 34 | -------------------------------------------------------------------------------- /examples/working-compiler/dom.test: -------------------------------------------------------------------------------- 1 | ../working/dom.ey -------------------------------------------------------------------------------- /examples/working-compiler/dom2.test: -------------------------------------------------------------------------------- 1 | [ 7 7 7 7 7 ] dom dump 2 | "foo" dom dump 3 | -------------------------------------------------------------------------------- /examples/working-compiler/each.test: -------------------------------------------------------------------------------- 1 | ../working/each.ey -------------------------------------------------------------------------------- /examples/working-compiler/elymas.ey: -------------------------------------------------------------------------------- 1 | ../../compiler/elymas.ey -------------------------------------------------------------------------------- /examples/working-compiler/elymasAsm.ey: -------------------------------------------------------------------------------- 1 | ../../compiler/elymasAsm.ey -------------------------------------------------------------------------------- /examples/working-compiler/elymasAsmLib.ey: -------------------------------------------------------------------------------- 1 | ../../compiler/elymasAsmLib.ey -------------------------------------------------------------------------------- /examples/working-compiler/elymasGlobal.ey: -------------------------------------------------------------------------------- 1 | ../../compiler/elymasGlobal.ey -------------------------------------------------------------------------------- /examples/working-compiler/elymasLexer.ey: -------------------------------------------------------------------------------- 1 | ../../compiler/elymasLexer.ey -------------------------------------------------------------------------------- /examples/working-compiler/exec.test: -------------------------------------------------------------------------------- 1 | ../working/exec.ey -------------------------------------------------------------------------------- /examples/working-compiler/fib.test: -------------------------------------------------------------------------------- 1 | ../working/fib.ey -------------------------------------------------------------------------------- /examples/working-compiler/fold.test: -------------------------------------------------------------------------------- 1 | ../working/fold.ey -------------------------------------------------------------------------------- /examples/working-compiler/freeze.test: -------------------------------------------------------------------------------- 1 | { "Hallo Welt" dump 0 sys .exit } "frozen" sys .freeze 2 | -------------------------------------------------------------------------------- /examples/working-compiler/freeze2.test: -------------------------------------------------------------------------------- 1 | [ "foo" "bar" "quux" ] { 2 | _ { dump 0 sys .exit }_ -01 ".bin" cat sys .freeze 3 | } each 4 | -------------------------------------------------------------------------------- /examples/working-compiler/grammar-pre.test: -------------------------------------------------------------------------------- 1 | [ "(" ")" "[" "]" "-" "|" ] { _ { eq }_ "'" -102 cat deff }' each 2 | 3 | "[" '[ dump 4 | "x" '[ dump 5 | -------------------------------------------------------------------------------- /examples/working-compiler/grep-fast.test: -------------------------------------------------------------------------------- 1 | "{ =*p [ -01 { _ p not \"--\" | rep }\" each ] } *" ==grepCode 2 | 3 | { grepCode includeLine /including dump } /fastGrep defq 4 | 5 | [ 1 2 3 4 5 6 7 8 9 10 ] ==data 6 | 7 | 1000000 { 8 | data { 5 eq } fastGrep -- 9 | } rep 10 | 11 | 5 ==i 12 | 13 | 1000000 { 14 | data { i eq }" fastGrep -- 15 | } rep 16 | -------------------------------------------------------------------------------- /examples/working-compiler/grep.test: -------------------------------------------------------------------------------- 1 | ../working/grep.ey -------------------------------------------------------------------------------- /examples/working-compiler/hash-set.test: -------------------------------------------------------------------------------- 1 | ../working/hash-set.ey -------------------------------------------------------------------------------- /examples/working-compiler/include-and-macro.ey: -------------------------------------------------------------------------------- 1 | { 2 | /ok ==ok 3 | "include-and-macro.inc" include 4 | } * 5 | -------------------------------------------------------------------------------- /examples/working-compiler/include-and-macro.inc: -------------------------------------------------------------------------------- 1 | 5 { dump ok dump }_ * 2 | -------------------------------------------------------------------------------- /examples/working-compiler/include.test: -------------------------------------------------------------------------------- 1 | "included" dump 2 | 3 | scope dump 4 | 5 | 1 0 add 6 | { -- 0 } /add deff 7 | 8 | { < scope dump 9 | "/home/drahflow/elymas/examples/working-compiler/include.test" include 10 | > } rep 11 | -------------------------------------------------------------------------------- /examples/working-compiler/int.test: -------------------------------------------------------------------------------- 1 | ../working/int.ey -------------------------------------------------------------------------------- /examples/working-compiler/io.test: -------------------------------------------------------------------------------- 1 | # ## variant 0 2 | # 3 | # < sys .file with 4 | # "io.ey" RO open 5 | # 512 read 6 | # close 7 | # > - 8 | 9 | ## variant 1 10 | 11 | sys .file /f defv 12 | "io.test" f .open 13 | 512 f .read 14 | f .close 15 | 16 | sys .out .writeall 17 | -------------------------------------------------------------------------------- /examples/working-compiler/keys.ey: -------------------------------------------------------------------------------- 1 | < 2 | 1 ==a 3 | 2 ==b 4 | 3 ==c 5 | 4 ==d 6 | 5 ==e 7 | 6 ==f 8 | 7 ==g 9 | 8 ==h 10 | 9 ==i 11 | > keys dump 12 | -------------------------------------------------------------------------------- /examples/working-compiler/len.test: -------------------------------------------------------------------------------- 1 | ../working/len.ey -------------------------------------------------------------------------------- /examples/working-compiler/list-spell.ey: -------------------------------------------------------------------------------- 1 | # Implementing the list spell by Aphyr 2 | 3 | { ==h { h ? 1 }_ } =*cons 4 | 5 | { } "3" cons "2" cons "1" cons ==x 6 | x dump 7 | 8 | { =*l _ { 1 sub 1 l -- nth } { -- 0 l -- } ? * } =*nth 9 | 10 | { [ -01 { 0 -01*1 -01 } { 1 -01* -- } loop -1 ] dump } =*dumpList 11 | 12 | x dumpList 13 | 14 | { { { } } -01 15 | { =*r =*l 16 | 0 l { 17 | { -1*0 cons } 1 l -- |r r 18 | } rep 19 | } _ * * 20 | } =*reverse 21 | 22 | x reverse dumpList 23 | -------------------------------------------------------------------------------- /examples/working-compiler/lookup-constant.ey: -------------------------------------------------------------------------------- 1 | 0 ==:someName 2 | 3 | { { { 4 | 5000000 { someName -- } rep 5 | } } } * * * 6 | 7 | "done" dump 8 | -------------------------------------------------------------------------------- /examples/working-compiler/lookup-dynamic.ey: -------------------------------------------------------------------------------- 1 | 0 ==?someName 2 | 3 | { { { 4 | 5000000 { someName -- } rep 5 | } } } * * * 6 | 7 | "done" dump 8 | -------------------------------------------------------------------------------- /examples/working-compiler/lookup-static.ey: -------------------------------------------------------------------------------- 1 | 0 ==someName 2 | 3 | { { { 4 | 5000000 { someName -- } rep 5 | } } } * * * 6 | 7 | "done" dump 8 | -------------------------------------------------------------------------------- /examples/working-compiler/loop.test: -------------------------------------------------------------------------------- 1 | ../working/loop.ey -------------------------------------------------------------------------------- /examples/working-compiler/member-functions.test: -------------------------------------------------------------------------------- 1 | < 2 | { keys dump } /k defmd 3 | > ==c 4 | 5 | < c >' .k 6 | 7 | { 8 | < c >' .k 9 | } _ * * 10 | -------------------------------------------------------------------------------- /examples/working-compiler/postgresql.test: -------------------------------------------------------------------------------- 1 | "lib/ffi.ey" include 2 | "lib/ffi/pq.ey" include 3 | 4 | { 5 | "dbname=template1" ffi .pq .functional ">>" deffd 6 | "2015-01-01" >>SELECT * FROM pg_stat_activity WHERE backend_start > $1 { ==row 7 | row keys { ==k 8 | k ": " cat row k . cat dump 9 | } each 10 | } each 11 | } { 12 | "Something went wrong with PostgreSQL: " -01 .msg cat die 13 | } ?!io.ffi.pq 14 | 15 | # vim: syn=elymas 16 | -------------------------------------------------------------------------------- /examples/working-compiler/qsort.test: -------------------------------------------------------------------------------- 1 | ../working/qsort.ey -------------------------------------------------------------------------------- /examples/working-compiler/range.test: -------------------------------------------------------------------------------- 1 | ../working/range.ey -------------------------------------------------------------------------------- /examples/working-compiler/regex.test: -------------------------------------------------------------------------------- 1 | ../working/regex.ey -------------------------------------------------------------------------------- /examples/working-compiler/remaining-stack.ey: -------------------------------------------------------------------------------- 1 | sys .asm .ops ==:sysasmops 2 | { 3 | quoted { 4 | _ sys .typed .type 1 eq { 5 | sysasmops -01 .| 6 | } { 7 | "sysasmops" "|" | -102 "." | 8 | } ? * 9 | } { 10 | sysasmops -01 . 11 | } ? * 12 | } ":" defq 13 | { :labelRecord [ } "[[" deff 14 | { ] :labelResolve } "]]" deff 15 | sysasmops .|label "@" deff 16 | 17 | 6148914691236516950 ==STACKTOPMARKER 18 | 19 | # Count unused cells up to top of data stack 20 | # 0 <- number of remaining stack cells 21 | [[ 22 | /rbx :popqReg 23 | 24 | /rcx /rcx :xorqRegReg 25 | /rcx :decqReg 26 | STACKTOPMARKER /rax :movqImmReg 27 | /rsp /rdi :movqRegReg 28 | :std 29 | :repnz :scasq 30 | :cld 31 | /rcx :negqReg 32 | 63 /rcx :btsqImm8Reg 33 | /rcx :pushqReg 34 | 35 | /rbx :pushqReg 36 | :retn 37 | ]] [ ] sys .asm .createFunction =*remainingDataStack 38 | 39 | # Count unused cells up to top of call stack 40 | # 0 <- number of remaining stack cells 41 | [[ 42 | /rbx :popqReg 43 | 44 | /rcx /rcx :xorqRegReg 45 | /rcx :decqReg 46 | STACKTOPMARKER /rax :movqImmReg 47 | /r15 /rdi :movqRegReg 48 | :std 49 | :repnz :scasq 50 | :cld 51 | /rcx :negqReg 52 | 63 /rcx :btsqImm8Reg 53 | /rcx :pushqReg 54 | 55 | /rbx :pushqReg 56 | :retn 57 | ]] [ ] sys .asm .createFunction =*remainingCallStack 58 | 59 | { 60 | remainingCallStack txt .produce .u dump 61 | f 62 | } _ =*f * 63 | 64 | # vim: syn=elymas 65 | -------------------------------------------------------------------------------- /examples/working-compiler/reverse.test: -------------------------------------------------------------------------------- 1 | ../working/reverse.ey -------------------------------------------------------------------------------- /examples/working-compiler/run_once.test: -------------------------------------------------------------------------------- 1 | { "}" | * 2 | { ==f 0 ==running 3 | { f } { * }" ; { =*f { running not { 1 =running f 0 =running } rep } } ; 4 | } * 5 | }" "}!" defq 6 | 7 | { 8 | 5 ==i 9 | 10 | { "g1 called" dump i dump f }! =*g1 11 | g1 12 | 13 | { "g2 called" dump i dump f }! =*g2 14 | g2 15 | } =*f 16 | 17 | f 18 | -------------------------------------------------------------------------------- /examples/working-compiler/scope-emulation.test: -------------------------------------------------------------------------------- 1 | "canary" 2 | < { -- -- "here: ?" dump } "#?" deffd > /foo /bar ? 3 | _ dump 4 | < { "here: *" dump } "#*" deffd > * 5 | _ dump 6 | < { "here: =[]" dump } "#=[]" deffd > =[] 7 | _ dump 8 | < { "here: len" dump } "#len" deffd > len 9 | _ dump 10 | /foo < { "here: cat (with: " -01 cat ")" cat dump } "#cat" deffd > cat 11 | _ dump 12 | < { "here: -01 cat (with: " -01 cat ")" cat dump } "#-01 cat" deffd > /foo cat 13 | _ dump 14 | < { -- "here: each" dump } "#each" deffd > { "xxx" die } each 15 | _ dump 16 | < { "here: dom" dump } "#dom" deffd > dom 17 | _ dump 18 | < { "here: !" dump "element count: " dump dump } "#!" deffd > 42 ! 19 | _ dump 20 | -------------------------------------------------------------------------------- /examples/working-compiler/scope-emulation2.test: -------------------------------------------------------------------------------- 1 | < 2 | "s" ==name 3 | { "s .#add" dump keys dump } "#add" deffd 4 | { "s .#-01 add" dump keys dump } "#-01 add" deffd 5 | "" ==s 6 | > ==s 7 | 8 | < 9 | "p" ==name 10 | { "p .#add" dump keys dump } "#add" deffd 11 | { "p .#-01 add" dump keys dump } "#-01 add" deffd 12 | "" ==p 13 | > ==p 14 | 15 | p s add 16 | -------------------------------------------------------------------------------- /examples/working-compiler/scope-macro.test: -------------------------------------------------------------------------------- 1 | { 2 | /outer_macro dump 3 | } /macro defq 4 | 5 | { 6 | { 7 | /inner_macro dump 8 | } "macro" defq 9 | 10 | /here dump 11 | macro 12 | /there dump 13 | } * 14 | 15 | macro 16 | -------------------------------------------------------------------------------- /examples/working-compiler/scope.test: -------------------------------------------------------------------------------- 1 | ../working/scope.ey -------------------------------------------------------------------------------- /examples/working-compiler/scoping.test: -------------------------------------------------------------------------------- 1 | ../working/scoping.ey -------------------------------------------------------------------------------- /examples/working-compiler/stackobjects.test: -------------------------------------------------------------------------------- 1 | { 2 | [ 1 2 3 4 5 6 7 8 ] 3 | { -0000000000000000000000000000 } 4 | -0*0*0*0*0*0*0*0*0*0*0*0*0*0* 5 | "some copies..." dump 6 | } 7 | -0*0*0*0*0*0*0*0*0*0*0*0*0*0* 8 | -------------------------------------------------------------------------------- /examples/working-compiler/stackops.test: -------------------------------------------------------------------------------- 1 | ../working/stackops.ey -------------------------------------------------------------------------------- /examples/working-compiler/standard.ey: -------------------------------------------------------------------------------- 1 | ../../compiler/standard.ey -------------------------------------------------------------------------------- /examples/working-compiler/str.test: -------------------------------------------------------------------------------- 1 | 0 3 "abcdef" str .infix dump 2 | 3 6 "abcdef" str .infix dump 3 | 0 2 neg "abcdef" str .infix dump 4 | 2 neg 6 "abcdef" str .infix dump 5 | 3 neg 1 neg "abcdef" str .infix dump 6 | 2 0 "abcdef" str .infix dump 7 | 2 neg "abcdef" str .postfix dump 8 | 2 "abcdef" str .prefix dump 9 | -------------------------------------------------------------------------------- /examples/working-compiler/strcat.test: -------------------------------------------------------------------------------- 1 | ../working/strcat.ey -------------------------------------------------------------------------------- /examples/working-compiler/streq_autoloop.test: -------------------------------------------------------------------------------- 1 | ../working/streq_autoloop.ey -------------------------------------------------------------------------------- /examples/working-compiler/string.test: -------------------------------------------------------------------------------- 1 | ../working/string.ey -------------------------------------------------------------------------------- /examples/working-compiler/stringassign.test: -------------------------------------------------------------------------------- 1 | "foo" ==f 2 | 64 1 f =[] 3 | f dump 4 | -------------------------------------------------------------------------------- /examples/working-compiler/stringexec.test: -------------------------------------------------------------------------------- 1 | "abc" _ 0 -01 * dump 2 | _ 1 -01 * dump 3 | _ 2 -01 * dump 4 | _ 3 -01 * dump 5 | -------------------------------------------------------------------------------- /examples/working-compiler/syscall.test: -------------------------------------------------------------------------------- 1 | 1 "Hallo Welt." _ len 0 0 0 1 sys .asm .syscall 2 | -------------------------------------------------------------------------------- /examples/working-compiler/ternary.test: -------------------------------------------------------------------------------- 1 | 0 /yes /no ? dump 2 | 1 /yes /no ? dump 3 | < { -- -- /lul } "?" deffd > ==s 4 | s dump 5 | s /yes /no ? dump 6 | -------------------------------------------------------------------------------- /examples/working-compiler/testing.test: -------------------------------------------------------------------------------- 1 | ../working/testing.ey -------------------------------------------------------------------------------- /examples/working-compiler/unclean-macro.test: -------------------------------------------------------------------------------- 1 | { ==text =*handler 2 | text "(.)=(.*)" regex -- < == > handler 3 | } /mappingParser deffst 4 | 5 | { ==scope ==w ==code ==text 6 | { ==var 7 | { var -01 . } 8 | < "$" deffst { * }' scope >' -- 9 | code -01 * 10 | /w_is: w cat dump 11 | } text mappingParser 12 | } /scopeSplicer deffst 13 | 14 | sys .|executeIdentifier "✨" deffd 15 | { "}\"" | * ✨w ✨scope ✨scopeSplicer }" "}✨" defq 16 | 17 | { /v_before ==v /w_before ==w 18 | "C=Hello World" { 19 | v dump 20 | $C dump 21 | /v_after =v 22 | /result 23 | }✨ dump 24 | v dump 25 | } * 26 | 27 | # vim: syn=elymas 28 | -------------------------------------------------------------------------------- /examples/working-compiler/undefined-resolution.test: -------------------------------------------------------------------------------- 1 | < 2 | { "#." dump dump } "#." deffd 3 | { "#.|" dump dump } "#.|" deffd 4 | { "#.?" dump dump } "#.?" deffd 5 | { "#.=" dump dump dump } "#.=" deffd 6 | > ==s 7 | 8 | < { |pipebare } =*f s >' .f 9 | < { 42 =equalbare } =*f s >' .f 10 | s .|dotpipe 11 | s .?dotquestion 12 | s .dot 13 | < { bare } =*f s >' .f 14 | 15 | { 16 | < { |pipebare } =*f s >' .f 17 | < { 42 =equalbare } =*f s >' .f 18 | s .|dotpipe 19 | s .?dotquestion 20 | s .dot 21 | < { bare } =*f s >' .f 22 | } _ * * 23 | -------------------------------------------------------------------------------- /examples/working-loaded/bufferedServer.test: -------------------------------------------------------------------------------- 1 | net .alg .bufferedEpollServer "+" via 2 | { ":" via < 3 | { :write "" } =*in 4 | { :close } _ =*end =*err 5 | > } +accept 6 | { 2001 } +port +run 7 | -------------------------------------------------------------------------------- /examples/working-loaded/catstrarray.ey: -------------------------------------------------------------------------------- 1 | /canary 2 | [ /a /b /c /d /e ] sys .asmroutines .catstrarray dump 3 | dump 4 | 5 | # vim: syn=elymas 6 | -------------------------------------------------------------------------------- /examples/working-loaded/error.test: -------------------------------------------------------------------------------- 1 | { ==file 2 | "trying to frobnicate file" dump file dump 3 | file "conf" eq 4 | 1 or 5 | { ??io.read } rep # oops, this failed 6 | "continuing frobnication..." dump 7 | } /frobnicateFile deffst 8 | 9 | { 10 | { ==doItManually 11 | "conf" ==file !!? ==restartFrobnication 12 | { 13 | file frobnicateFile 14 | } { 15 | -- < 16 | { "conf.bak" =file restartFrobnication 0 ! } =*useBackup 17 | { "Enter config by hand" dump doItManually 0 ! } =*manualEntry 18 | > ??!io 19 | } ?!io 20 | } { 21 | "manual entry starting (and grabbing stack)" dump 22 | } !!' 23 | } /frobnicateConfig deffst 24 | 25 | 26 | { 27 | { 28 | frobnicateConfig 29 | } { 30 | -- "fail :(" die 31 | } ?!io 32 | } /frobnicateUI deffst 33 | 34 | { 35 | { 36 | frobnicateConfig 37 | } { 38 | { 39 | "using backup config" dump .useBackup 40 | } { 41 | "last resort" dump .manualEntry 42 | } ?!io 43 | } ?!io 44 | } /frobnicateUIBetter deffst 45 | 46 | { 47 | { 48 | frobnicateConfig 49 | } [ 50 | { "using backup config" dump .useBackup } 51 | { "last resort" dump .manualEntry } 52 | ] ?!!io 53 | } /frobnicateUIBest deffst 54 | 55 | frobnicateUIBest 56 | 57 | # vim: syntax=elymas 58 | -------------------------------------------------------------------------------- /examples/working-loaded/httpServer.test: -------------------------------------------------------------------------------- 1 | net .alg .httpServer "+" via 2 | { 2002 } +port 3 | { ":" via 4 | :url dump 5 | [ 6 | { :url "/" eq } { 7 | "Hallo Welt!Test" 8 | "text/html" :ok 9 | } { :url "/test" eq } { 10 | "Test!" 11 | "text/html" :ok 12 | } { :url "/post" eq } { 13 | "" :body "" cat cat 14 | "text/html" :ok 15 | } 16 | ] conds 17 | } +request 18 | +run 19 | -------------------------------------------------------------------------------- /examples/working-loaded/interactive-stack.test: -------------------------------------------------------------------------------- 1 | { scope }' =*globalScope 2 | 3 | < 4 | map ==seenThings # from .hu of rawAddress to some name 5 | map ==usedNames # from name to rawAddress 6 | 7 | { ==suggested ==thing 8 | thing sys .asm .rawAddress _ ==a txt .produce .hu ==as 9 | 10 | globalScope keys { ==name 11 | globalScope name .| sys .asm .rawAddress _ ==a txt .produce .hu ==as 12 | 13 | "\e[2m" name cat "\e[0m" cat =name 14 | name as seenThings =[] 15 | a name usedNames =[] 16 | } each 17 | 18 | { ==i 19 | i 0 eq { 20 | i suggested * 21 | } { 22 | i suggested len math .base suggested * |cat fold 23 | } ? * 24 | } /toName deffst 25 | 26 | as seenThings .has { 27 | as seenThings * 28 | } { 29 | 0 ==i 30 | { 31 | i toName ==name 32 | name usedNames .has 33 | }' { 34 | { 1 add } |=i 35 | }' loop 36 | 37 | name as seenThings =[] 38 | a name usedNames =[] 39 | name 40 | } ? * 41 | } 42 | > -- /niceName deffd 43 | 44 | { [ "α" "β" "γ" "δ" "ε" "π" "φ" ] niceName } /niceScopeName deffd 45 | 46 | < 47 | [ 0 11 range { 48 | sys .asm .intToFloat 49 | }' each ] =*:FLOAT 50 | 51 | sys .out .|writeall =*out 52 | 53 | "0123456789" ==:base10digits 54 | "0123456789ABCDEF" ==:base16digits 55 | 56 | { _ 0 lt { neg "-" }' { "" }' ? * -01 57 | [ -01 16 { _ 16 umod base16digits * -01 16 udiv }' rep -- ] reverse str .fromArray cat 58 | }' /base16encode64 deffd 59 | 60 | { "\e[1;31m\e[0m" out }" /unknown defvd 61 | 62 | [ 63 | { "\e[31m" o txt .produce .i cat "\e[0m" cat out }" # integer 64 | { "\e[31m\"" o "\"\e[0m" cat cat out }" # string 65 | { "\e[31m" out o { ==f 0 ==e "+" ==s 0 ==i 66 | f 0 FLOAT lt { 0 FLOAT f sub =f "-" =s }' rep 67 | { f 1 FLOAT lt i 500 lt and }' { f 10 FLOAT mul =f e 1 sub =e i 1 add =i }' loop 68 | { f 10 FLOAT ge i 500 lt and }' { f 10 FLOAT div =f e 1 add =e i 1 add =i }' loop 69 | 70 | i 500 eq { 71 | s 72 | f 1 FLOAT lt "0.0e0" "inf" ? 73 | cat out 74 | }' { 75 | { 76 | 0 ==d 77 | 1 10 range { ==i f i FLOAT gt { i =d }' rep } each 78 | f d sub =f 79 | f 10 FLOAT mul =f 80 | d base10digits * 81 | } /extractDigit deffst 82 | 83 | [ 84 | 0 s * 85 | extractDigit 86 | 0 "." * 87 | 10 |extractDigit rep 88 | 0 "e" * 89 | e 0 lt { 90 | 0 e sub =e 91 | 0 "-" * 92 | } rep 93 | e 0 eq { 94 | 0 "0" * 95 | } rep 96 | [ 97 | { e } { 98 | e 10 mod base10digits * 99 | e 10 div =e 100 | } loop 101 | ] reverse _ len dearray 102 | ] str .fromArray out 103 | }' ? * 104 | } * "\e[0m" out }" # float 105 | unknown 106 | unknown # extension area 107 | { "\e[32m{" 108 | o [ /f /g /h /a /b /c /d /e ] niceName cat 109 | "\e[32m}\e[0m" cat out 110 | }" 111 | unknown 112 | { "\e[36m[" 113 | o [ /A /B /C /D /E /F /G /H ] niceName cat 114 | "\e[36m]\e[0m" cat out 115 | }" # array 116 | unknown # function type 117 | { "\e[35m<" 118 | o niceScopeName cat 119 | "\e[35m>\e[0m" cat out 120 | }" 121 | unknown # name table 122 | unknown # stack 123 | { "" cat out }" 124 | unknown 125 | unknown 126 | unknown 127 | { "[" out }" 128 | { "{" out }" 129 | { "\e[34m|\e[0m" out }" 130 | unknown 131 | ] /dumpActions deffd 132 | 133 | # dump top stack element 134 | { _ ==o sys .typed .type dumpActions * " " out } 135 | 136 | # dump entire stack 137 | { 0 ==i "" ==x 138 | { x sys .typed .type 18 neq } { 139 | i _' =x 140 | { 1 add } |=i 141 | } loop 142 | 143 | { 1 sub } |=i 144 | 145 | { i 0 ge } { 146 | i _' =x 147 | { 1 sub } |=i 148 | x objectdump 149 | " " out 150 | } loop 151 | 152 | "\n" out 153 | } 154 | > -- /stackdump deffd /objectdump deffd 155 | 156 | "Welcome to elymas.\n" sys .out .writeall 157 | 158 | { _ ==openedScope enincludeLine =*eval 159 | 1 ==running 160 | { 0 =running } =*quit 161 | 162 | { running } { 163 | "\n" sys .out .writeall 164 | "\e[35m" "scope" eval niceScopeName cat "\e[34m:\e[0m" cat sys .out .writeall 165 | "scope" eval _ ==curScope keys { ==name 166 | name existingGlobals .has not { 167 | " " sys .out .writeall name "=" cat sys .out .writeall curScope name .| objectdump 168 | } rep 169 | } each 170 | "\n" sys .out .writeall 171 | stackdump 172 | 173 | [ "\e[34m>" sys .out .writeall 174 | quoted { "\e[32m{" } rep "\e[0m \e[1m" ] |cat fold sys .out .writeall 175 | 65536 sys .in .read "\e[0m" sys .out .writeall _ len { ==line 176 | line "^(.*)\n$" regex { 177 | eval 178 | } { 179 | "non-terminal input" dump 180 | } ? * 181 | } { -- 182 | 0 =running 183 | } ? * 184 | } loop 185 | } /open deffd 186 | 187 | map ==existingGlobals 188 | globalScope keys { ==name 189 | 1 name existingGlobals =[] 190 | } each 191 | 192 | scope open 193 | 194 | "\n" sys .out .writeall 195 | 196 | # vim: syn=elymas 197 | -------------------------------------------------------------------------------- /examples/working-loaded/lib: -------------------------------------------------------------------------------- 1 | ../../elymas/lib -------------------------------------------------------------------------------- /examples/working-loaded/list.test: -------------------------------------------------------------------------------- 1 | list ==l 2 | list ==m 3 | 4 | /foo l .append 5 | /bar l .append 6 | /quux l .append 7 | 8 | l { dump } each 9 | 10 | [ /a /b /c ] m .append 11 | 12 | m { dump } each 13 | m len dump 14 | 15 | 2 m * dump 16 | 17 | [ /a /b /c ] m .append1 18 | 19 | m { dump } each 20 | 21 | list _ [ 1 2 3 ] -01 .append 22 | list _ [ 3 4 5 ] -01 .append 23 | add ==a 24 | 25 | a dump 26 | a len dump 27 | a |dump each 28 | 29 | a .pop 30 | 31 | a dump 32 | a len dump 33 | a |dump each 34 | 35 | 42 a .append 36 | 37 | a dump 38 | a len dump 39 | a |dump each 40 | -------------------------------------------------------------------------------- /examples/working-loaded/mapping.test: -------------------------------------------------------------------------------- 1 | < 2 | { .v -01 . } "#*" defmd 3 | { [ 0 ] } "#in" deffd 4 | { [ 0 ] } "#out" deffd 5 | { .v keys } "#dom" defmd 6 | { .v ==v =*f v keys { v -01 . f } each } "#each" defmd 7 | { 0 } "#istart" deffd 8 | { .v keys len eq } "#iend" defmd 9 | { 1 add } "#istep" deffd 10 | { .v keys * } "#itrans" defmd 11 | { < < { defv }' > ==v "#=[]" =* > } _ "#iclone" deffd 12 | > -- /map deffd 13 | 14 | { map } "(" deffd 15 | { } ")" deffd 16 | { -2102 =[] } "=>" deffd 17 | 18 | ( 19 | 0 =>foo 20 | 1 =>bar 21 | 2 =>quux 22 | ) ==m 23 | 24 | { _ ==m dom { 25 | _ ": " cat -01 m * txt .produce .u cat dump 26 | } each 27 | } /mdump deffd 28 | 29 | "foo" m * dump 30 | "bar" m * dump 31 | "quux" m * dump 32 | 33 | m mdump 34 | 35 | 5 m add ==mm 36 | 37 | mm mdump 38 | -------------------------------------------------------------------------------- /examples/working-loaded/parser.test: -------------------------------------------------------------------------------- 1 | parser .glr ":" via 2 | 3 | /S :nonterminal ==S 4 | /expr :nonterminal ==expr 5 | /num :nonterminal ==num 6 | 7 | S [ expr ] { :0 } :rule 8 | expr [ num ] { :0 } :rule 9 | expr [ expr "+" expr ] { ==s s :2 s :0 add } :rule 10 | expr [ expr "-" expr ] { ==s s :2 s :0 sub } :rule 11 | expr [ "(" expr ")" ] { ==s s :1 } :rule 12 | num [ /0 ] { -- 0 } :rule 13 | num [ /1 ] { -- 1 } :rule 14 | num [ /2 ] { -- 2 } :rule 15 | 16 | [ S :automaton ==Sparser ] len 0 gt { "stack garbage" die } rep 17 | 18 | "generation done" dump 19 | 20 | 100000 { 21 | Sparser .run =*consume 22 | [ "(" "(" /2 "+" /1 "-" /1 ")" ")" "+" /1 ] { _ consume -- } each 23 | "" _ consume :result ==result 24 | }' rep 25 | 26 | result dump 27 | -------------------------------------------------------------------------------- /examples/working-loaded/sha512.test: -------------------------------------------------------------------------------- 1 | 100 { 2 | "" crypt .sha512 .hex dump 3 | "Test" crypt .sha512 .hex dump 4 | "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" crypt .sha512 .hex dump 5 | } rep 6 | -------------------------------------------------------------------------------- /examples/working-loaded/sort.test: -------------------------------------------------------------------------------- 1 | "lib/sort.ey" include 2 | 3 | [ 99 7 2 3 ] |lt order dump 4 | map ==m 5 | 6 | 99 /foo m =[] 7 | 7 /bar m =[] 8 | 2 /quux m =[] 9 | 3 /baz m =[] 10 | 11 | m sort dump 12 | -------------------------------------------------------------------------------- /examples/working-loaded/wrapper.test: -------------------------------------------------------------------------------- 1 | map ==m 2 | m 7 default ==md 3 | 4 | 5 /foo md =[] 5 | /foo md * dump 6 | /bar md * dump 7 | md dom dump 8 | 9 | list ==l 10 | l 7 default ==ld 11 | 12 | 5 ld .append1 13 | 0 ld * dump 14 | 12 ld * dump 15 | ld dom dump 16 | -------------------------------------------------------------------------------- /examples/working-loaded/xml.test: -------------------------------------------------------------------------------- 1 | "lib/xml.ey" include 2 | 3 | { ==indent ==elem 4 | indent { " " sys .out .writeall } rep 5 | elem .name "" eq { 6 | elem .text sys .out .writeall "\n" sys .out .writeall 7 | } { 8 | elem .name sys .out .writeall "\n" sys .out .writeall 9 | elem .children { 10 | indent 2 add dumpTree 11 | } each 12 | } ? * 13 | } /dumpTree deffst 14 | 15 | sys .file ":" via 16 | "xml.test.xml" :open 17 | 65536 :read ==content 18 | :close 19 | 20 | 1 ==success 21 | { 22 | content xml .parse 23 | } { 24 | "Error during parse, remaining content: " dump 25 | .remaining dump 26 | 0 =success 27 | } ?!parse 28 | 29 | success { 0 dumpTree } rep 30 | 31 | # vim: syn=elymas 32 | -------------------------------------------------------------------------------- /examples/working-loaded/xml.test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jens-Wolfhard Schicke - Drahflow - Welcome to my Homepage 6 | 7 | 8 | 18 |

Welcome to my Homepage

19 |

20 | Here I'll try to help anybody who (by what ever accident was necessary) 21 | found this page, in using Linux and C(++). Feel free to browse whatever 22 | files you encounter and mail 23 | me whenever you have questions. This page does not use much images 24 | mainly because I'm completely unable to design anything with graphics 25 | so I stay with text. Additionally this provides you with faster load 26 | times, although these don't matter much anymore in times of flatrates. 27 |

28 |

29 | As a response to recent fancy ideas of our Government, I now support the 30 | German Pirate Party 31 | trying to stop the increasing surveillance in our country. 32 |

33 |

34 | 35 | VIm Logo 36 | 37 | This is by far the 38 | best text-editor 39 | I ever encountered. Once you read 40 | all the help files you have thousands of commands just a few keystrokes 41 | away. 42 |

43 | 44 |

45 | 46 | Valid HTML 4.01! 47 | 48 | The 49 | W3C HTML Validator 50 | states that this page is valid HTML 4.01, actually not does not mean a 51 | thing because not all browsers are W3C compliant but at least it looks 52 | nice, doesn't it? 53 |

54 | 55 |

56 | 57 | Valid CSS! 58 | 59 | Another test of W3C, this time it's a 60 | CSS test 61 | for this page, which also returned this to be a valid page. 62 |

63 | 64 |

65 | 66 | powered by Linux 67 | 68 | And of course this server runs on 69 | Linux 70 | the best operating system I got used to since now. 71 | BSD is quite nice, too, but I not yet 72 | relly dug myself into it. 73 |

74 | 75 |

76 | 77 | powered by Apache 78 | 79 | This site is powered by 80 | Apache, 81 | one of the most often used Linux Webservers around. 82 |

83 | 84 |

85 | 86 | Aktion UBERWACH! 87 | 88 | Don't be intimidated. The image referenced will only log accesses by our most beloved government. 89 |

90 | 91 | 92 | -------------------------------------------------------------------------------- /examples/working-shared/gtk.ey: -------------------------------------------------------------------------------- 1 | "lib/ffi.ey" include 2 | "lib/ffi/gtk.ey" include 3 | 4 | { γbutton_new_with_label } "β" deffd 5 | { -2201 0 0 0 γsignal_connect_data } "<-" deffd 6 | 7 | ffi .gtk "γ" via 8 | "org.gtk.example" 0 γapplication_new ==app 9 | app "activate" { dump dump 10 | app γapplication_window_new ==win 11 | win "Window" γwindow_set_title 12 | win 200 200 γwindow_set_default_size 13 | 14 | γORIENTATION_HORIZONTAL γbutton_box_new ==box 15 | win 10 γcontainer_set_border_width 16 | 17 | γgrid_new ==grid 18 | win grid γcontainer_add 19 | 20 | βHello World! 21 | { dump dump "Hello World!" dump } <-clicked 22 | grid -01 0 0 1 1 γgrid_attach 23 | 24 | βFinish 25 | { dump dump win γwidget_destroy } <-clicked 26 | grid -01 1 0 1 1 γgrid_attach 27 | 28 | γtext_view_new ==txt 29 | txt 0 γtext_view_set_editable 30 | txt 0 γtext_view_set_cursor_visible 31 | txt γtext_view_get_buffer 32 | sys .file "φ" via "gtk.ey" φopen 65536 φread φclose 33 | γtext_buffer_set_text 34 | 35 | 0 0 γscrolled_window_new ==scroll 36 | scroll txt γcontainer_add 37 | scroll 1 γwidget_set_hexpand 38 | scroll 1 γwidget_set_vexpand 39 | grid scroll 0 1 2 1 γgrid_attach 40 | 41 | win γwidget_show_all 42 | } 0 0 0 γsignal_connect_data 43 | app 0 "" γapplication_run 44 | app γobject_unref 45 | 46 | "Killing threads with fire" die 47 | 48 | # vim: syn=elymas 49 | -------------------------------------------------------------------------------- /examples/working-shared/sdl.ey: -------------------------------------------------------------------------------- 1 | "lib/ffi.ey" include 2 | "lib/ffi/sdl.ey" include 3 | 4 | ffi .sdl ":" via 5 | 6 | :INIT_VIDEO :Init { 7 | :GetError dump 8 | "Init failed" die 9 | } rep 10 | 11 | "Ohai!" 0 0 800 600 0 :CreateWindow ==w 12 | 13 | w :GetWindowSurface ==s 14 | s 255 :Fill dump 15 | w :UpdateWindowSurface 16 | 17 | 1 sys .out .read dump 18 | :Quit 19 | 20 | # vim: syn=elymas 21 | -------------------------------------------------------------------------------- /examples/working/abstract-right.ey: -------------------------------------------------------------------------------- 1 | 0 4 range 5 add dump "test" dump 2 | -------------------------------------------------------------------------------- /examples/working/array-assign.ey: -------------------------------------------------------------------------------- 1 | [ 1 2 3 4 ] /a defv 2 | 0 6 a =[] 3 | 4 | a dump 5 | -------------------------------------------------------------------------------- /examples/working/array-list.ey: -------------------------------------------------------------------------------- 1 | < 2 | [ 0 1 2 ] /list defv 3 | 4 | { 5 | list [ -102 ] cat =list 6 | } 7 | 8 | { 9 | list 10 | } 11 | > -- /content deff /append deff 12 | 13 | 3 append 14 | 4 append 15 | 5 append 16 | 17 | content dump 18 | -------------------------------------------------------------------------------- /examples/working/arraycat.ey: -------------------------------------------------------------------------------- 1 | [ 1 2 3 ] [ 4 5 6 ] cat dump 2 | -------------------------------------------------------------------------------- /examples/working/arraylimits.ey: -------------------------------------------------------------------------------- 1 | < 2 | "]" | "]]" deffd 3 | 4 | { 5 | ]] _ =*a len ==l 6 | { 7 | _ 0 lt { "index too low" die } rep 8 | _ l ge { "index too high" die } rep 9 | a 10 | } 11 | } 12 | > -- "]" deffd 13 | 14 | [ 1 2 3 ] =*a 15 | 16 | 1 a 17 | 7 a 18 | -------------------------------------------------------------------------------- /examples/working/arrays.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | 1 /testValue defv 4 | { testValue and 5 | _ /testValue defv 6 | { } { "test failed" die } ? * 7 | } /test deff 8 | 9 | 3 4 add 10 | 7 eq test 11 | [ 4 7 ] 12 | -00 13 | 0 -01 * 4 eq test 14 | 1 -01 * 7 eq test 15 | 3 [ -0111 ] 16 | -000 17 | 0 -01 * 3 eq test 18 | 1 -01 * 3 eq test 19 | 2 -01 * 3 eq test 20 | 1 [ 4 7 ] * 21 | 7 eq test 22 | 3 [ 4 7 ] add 23 | -00 24 | 0 -01 * 7 eq test 25 | 1 -01 * 10 eq test 26 | [ 1 2 3 ] _ add 27 | -000 28 | 0 -01 * 2 eq test 29 | 1 -01 * 4 eq test 30 | 2 -01 * 6 eq test 31 | -------------------------------------------------------------------------------- /examples/working/asm.ey: -------------------------------------------------------------------------------- 1 | sys .asm /asm defv 2 | 3 | 4096 asm .alloc /e defv 4 | 5 | 195 e .base asm .poke 6 | 7 | e .base asm .execute 8 | e .free 9 | -------------------------------------------------------------------------------- /examples/working/bor.ey: -------------------------------------------------------------------------------- 1 | 16 2 bor dump 2 | -------------------------------------------------------------------------------- /examples/working/cat.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | 1 { } { 4 | 4096 sys .in .read 5 | _ sys .out .writeall 6 | len 7 | } loop 8 | -------------------------------------------------------------------------------- /examples/working/complex-exec.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | 3 { 2 add } |mul -21*20* dump # should be 0000F 4 | -------------------------------------------------------------------------------- /examples/working/concat.ey: -------------------------------------------------------------------------------- 1 | { 2 add } /f deff 2 | { 3 mul } /g deff 3 | 4 | 1 f g dump 5 | 1 { f g } * dump 6 | 7 | |f |g ; /h deff 8 | 9 | 1 h dump 10 | 11 | { /ff defv 12 | { 1 2 3 } ff ; ff ; 13 | } /test deff 14 | 15 | |add test * dump 16 | -------------------------------------------------------------------------------- /examples/working/dom.ey: -------------------------------------------------------------------------------- 1 | [ 7 7 7 7 7 ] dom dump 2 | -------------------------------------------------------------------------------- /examples/working/each.ey: -------------------------------------------------------------------------------- 1 | |defv "==" deff 2 | 3 | [ 1 2 3 ] { ==i i dump } each 4 | -------------------------------------------------------------------------------- /examples/working/exec.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | 1 1 |dump -110 * add dump 4 | 3 { 4 add } * dump 5 | 4 3 { 1 add } rep dump 6 | -------------------------------------------------------------------------------- /examples/working/fib.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | { ? * } /if deff 4 | 5 | { 6 | _ 0 eq -101 1 eq add 7 | { -- 1 } 8 | { 9 | _ 1 sub "fib" | * 10 | -01 2 sub "fib" | * 11 | add 12 | } 13 | if 14 | } /fib deff 15 | 16 | 7 fib dump 17 | -------------------------------------------------------------------------------- /examples/working/fold.ey: -------------------------------------------------------------------------------- 1 | |defv "==" deff 2 | 3 | { ==f ==a a len ==l 4 | l { 5 | 0 a * 6 | 1 l range { a * f * } each 7 | } { "fold on empty array" die } 8 | ? * 9 | } /fold deff 10 | 11 | { ==f _ len ==l l dearray l 1 sub f rep } /foldshort deff 12 | 13 | { ==f { f fold } } /enfold deff 14 | 15 | [ 1 2 3 ] 16 | _ |add fold dump 17 | _ |add foldshort dump 18 | _ |add enfold * dump 19 | -- 20 | -------------------------------------------------------------------------------- /examples/working/grep.ey: -------------------------------------------------------------------------------- 1 | { /p deff { 2 | [ -01 { _ p { } { -- } ? * } each ] 3 | } } /engrep deff 4 | 5 | { engrep * } /grep deff 6 | { -110 ; engrep |dom -20*1* } /indices deff 7 | 8 | { /p deff _ /a deff len /l defv 9 | 1 neg /r defv 10 | 11 | 0 { 12 | _ l lt 1 neg r eq and 13 | } { 14 | _ a p { _ =r } { } ? * 15 | 1 add 16 | } loop -- 17 | r 18 | } /index deff 19 | 20 | [ 1 2 3 4 5 6 7 8 9 ] { 2 mod } grep dump 21 | [ 1 3 4 5 6 7 8 9 ] { 2 mod } indices dump 22 | [ 1 3 4 5 6 7 8 9 ] { 6 eq } index dump 23 | [ 0 0 0 1 0 0 1 1 ] { } indices dump 24 | -------------------------------------------------------------------------------- /examples/working/hash-set.ey: -------------------------------------------------------------------------------- 1 | < { defv }' /put deff > /hashSet defv 2 | 3 | 1 /one hashSet .put 4 | 2 /two hashSet .put 5 | 6 | hashSet .one dump 7 | hashSet .two dump 8 | hashSet keys dump 9 | 10 | { 11 | < { defv }' /put deff > /hashSetB defv 12 | 13 | 1 /one hashSetB .put 14 | 2 /two hashSetB .put 15 | 16 | hashSetB .one dump 17 | hashSetB .two dump 18 | hashSetB 19 | } * keys dump 20 | -------------------------------------------------------------------------------- /examples/working/include.ey: -------------------------------------------------------------------------------- 1 | 1 0 add 2 | { -- 0 } /add deff 3 | 4 | "included" dump 5 | 6 | { 7 | "include.ey" include 8 | } rep 9 | -------------------------------------------------------------------------------- /examples/working/int.ey: -------------------------------------------------------------------------------- 1 | 1 1 add -- 2 | 0 dump 3 | 1 dump 4 | 2 dump 5 | 1 1 add dump 6 | 1 2 add dump 7 | 2 1 add dump 8 | -------------------------------------------------------------------------------- /examples/working/io.ey: -------------------------------------------------------------------------------- 1 | # ## variant 0 2 | # 3 | # < sys .file with 4 | # "io.ey" RO open 5 | # 512 read 6 | # close 7 | # > - 8 | 9 | ## variant 1 10 | 11 | sys .file /f defv 12 | "io.ey" f .open 13 | 512 f .read 14 | f .close 15 | 16 | sys .out .writeall 17 | -------------------------------------------------------------------------------- /examples/working/len.ey: -------------------------------------------------------------------------------- 1 | "abcdef" len dump 2 | [ 1 2 3 4 ] len dump 3 | -------------------------------------------------------------------------------- /examples/working/loop.ey: -------------------------------------------------------------------------------- 1 | 50 { _ 30 gt } { _ dump 1 sub } loop dump 2 | -------------------------------------------------------------------------------- /examples/working/macro.ey: -------------------------------------------------------------------------------- 1 | # an alternative to }, moving the top stack element 2 | # into closure storage and pushing it back before 3 | # executing the block 4 | 5 | { "}" | * 6 | { /f deff /x defv 7 | { x f } 8 | } quoted { } { * } ? * 9 | } "}_" defq 10 | 11 | 5 { { dump }_ } * /dumpfive deff 12 | 5 { dump }_ /dumpfivetwo deff 13 | 14 | 7 dumpfive -- 15 | 7 dumpfivetwo -- 16 | 17 | 18 | # import members of other objects into local scope 19 | 20 | { 21 | "_" | "021" | "-" | ".|" | "01" | "-" | |deff 22 | } /usef defq 23 | 24 | 25 | # codewalker 26 | 27 | { "lol" dump } /lol deff 28 | 29 | { 30 | 1 /cont defv 31 | 32 | { cont } { 0 { 33 | exe /walkelem deff 34 | { sys .out .writestr } /out deff 35 | 36 | _ { { " " out } rep }_ /indent deff 37 | { 2 add walkelem }_ /walk deff 38 | 39 | _ code [ { 40 | indent [ "\"" -102 "\"\n" ] |out each 41 | } { 42 | indent _ sym _ out 43 | "{" eq { 0 =cont |lol } { -- } ? * 44 | "\n" out 45 | } { 46 | blk |walk each 47 | } ] * * 48 | } * } loop 49 | } /codewalk defq 50 | 51 | { f "t" g h { a b { c d } e } codewalk } * 52 | -------------------------------------------------------------------------------- /examples/working/qsort.ey: -------------------------------------------------------------------------------- 1 | [ 23 3 43 37 89 11 21 4 35 94 28 36 96 95 51 7 59 57 48 68 85 73 6 67 71 92 76 14 31 18 64 30 9 41 34 86 33 75 70 81 27 93 8 100 55 39 1 61 42 45 29 5 17 79 13 90 49 99 91 69 46 54 16 53 40 62 60 20 88 97 12 74 15 65 72 80 50 44 47 24 25 2 58 52 78 83 10 84 98 19 56 87 26 32 22 63 82 77 0 38 66 ] /data defv 2 | 3 | { "=[]" | -31*21*310*210* } /swap deff 4 | 5 | { /a defv /end defv /start defv 6 | end a * /pivot defv 7 | start /store defv 8 | 9 | start end range { /i defv 10 | i a * pivot lt { 11 | store _ i a swap 12 | 1 add =store 13 | } rep 14 | } each 15 | 16 | store _ end a swap 17 | _ 1 sub start -0101 lt { a qsort } { -2 } ? * 18 | 1 add end -1010 lt { a qsort } { -2 } ? * 19 | } /qsort deff 20 | 21 | { _ len _ 0 gt { 1 sub 0 -012 qsort } rep } /sort deff 22 | 23 | data _ sort dump 24 | -------------------------------------------------------------------------------- /examples/working/range.ey: -------------------------------------------------------------------------------- 1 | 0 10 range dump 2 | -------------------------------------------------------------------------------- /examples/working/recursion.ey: -------------------------------------------------------------------------------- 1 | 5 2 | { exe =e 3 | 1 sub 4 | _ dump 5 | _ { e * } { } ? * 6 | } * 7 | -------------------------------------------------------------------------------- /examples/working/regex.ey: -------------------------------------------------------------------------------- 1 | "\"include\" dump\n" "([^\\n]*)\\n(.*)" regex 2 | dump dump dump 3 | 4 | "the quick brown fox jumps over the lazy dog" 5 | { "(the)(.*)" regex } { dump } loop 6 | "abcdefghijklmnopqrstuvwxyz" 7 | { "([d-h][d-h])(.*)" regex } { dump } loop 8 | "abcdefghijklmnopqrstuvwxyz" 9 | { "^(...)(.*)" regex } { dump } loop 10 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 11 | "(...)$" regex { dump } rep 12 | 13 | " code" 14 | { _ "^ (.*)" regex } { -01 -- } loop dump 15 | "# comment" 16 | "^#" regex dump 17 | "1234 remaining" 18 | "^(\\d+) +(.*)" regex dump dump dump 19 | "\"stringcontent..." 20 | "^\"(.*)" regex dump dump 21 | "\\\\remaining" 22 | "^\\\\\\\\(.*)" regex dump dump 23 | "\\nremaining" 24 | "^\\\\n(.*)" regex dump dump 25 | "\\0foo" 26 | "^\\\\0(.*)" regex dump dump 27 | "\\0" 28 | "^\\\\0(.*)" regex dump dump 29 | "\\\"remaining" 30 | "^\\\\\"(.*)" regex dump dump 31 | "abcdef" 32 | { "([^c])(.*)" regex } { dump } loop 33 | "...stringcontent\"" 34 | { "^([^\"\\\\])(.*)" regex } { dump } loop 35 | "/quoted123 remaining" 36 | "^([^a-zA-Z0-9 ]+)([a-zA-Z0-9][^ ]*) +(.*)" regex dump dump dump 37 | "unquoted remaining" 38 | "^([a-zA-Z0-9]+|[^a-zA-Z0-9 ]+) +(.*)" regex dump dump dump 39 | "+++ remaining" 40 | "^([a-zA-Z0-9]+|[^a-zA-Z0-9 ]+) +(.*)" regex dump dump dump 41 | -------------------------------------------------------------------------------- /examples/working/reverse.ey: -------------------------------------------------------------------------------- 1 | { _ /a deff len /l defv 2 | [ 1 l 1 add range { l -01 sub a } each ] 3 | } /reverse deff 4 | 5 | [ 3 2 1 ] reverse dump 6 | -------------------------------------------------------------------------------- /examples/working/scope.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | < 4 | 1 /a defv 5 | 2 /b defv 6 | { "yes" dump } /c deff 7 | > 8 | 9 | -000 .a dump 10 | .b dump 11 | .c 12 | 13 | < < 14 | "closure" /x defv 15 | { x } 16 | > -- /get deff > 17 | 18 | .get dump 19 | -------------------------------------------------------------------------------- /examples/working/scoping.ey: -------------------------------------------------------------------------------- 1 | 42 { /i defv { i } } * * dump 2 | -------------------------------------------------------------------------------- /examples/working/stackops.ey: -------------------------------------------------------------------------------- 1 | 1 2 3 -012 -- -- -- 2 | 1 2 3 -111111111 -9 -- 3 | [ 1 2 3 ] dump 4 | [ 1 2 3 -210 ] dump 5 | [ 1 2 3 -012 ] dump 6 | -------------------------------------------------------------------------------- /examples/working/strcat.ey: -------------------------------------------------------------------------------- 1 | "abc" "def" cat 2 | 4 "abcdef" str .postfix die 3 | -------------------------------------------------------------------------------- /examples/working/streq_autoloop.ey: -------------------------------------------------------------------------------- 1 | /a /a eq dump 2 | /d [ /a /b /c /d /e /f /g /h ] eq dump 3 | -------------------------------------------------------------------------------- /examples/working/string.ey: -------------------------------------------------------------------------------- 1 | "test" dump 2 | "a\nb" dump 3 | "a\\b" dump 4 | "a\"b" dump 5 | "thisisalongstring" dump 6 | /bare dump 7 | -------------------------------------------------------------------------------- /examples/working/suspend.ey: -------------------------------------------------------------------------------- 1 | 0 10 range { ==i 2 | i dump 3 | i 5 eq { 4 | { _ { * }_ "coroutine-suspend" sys .freeze * } !! * 5 | } rep 6 | } each 7 | -------------------------------------------------------------------------------- /examples/working/syscall.ey: -------------------------------------------------------------------------------- 1 | "not available in the interpreter" die 2 | -------------------------------------------------------------------------------- /examples/working/testing.ey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env elymas 2 | 3 | 1 /testValue defv 4 | { testValue and 5 | _ /testValue defv 6 | { } { "test failed" die } ? * 7 | } /test deff 8 | 9 | 1 test 10 | 1 test 11 | 0 test 12 | -------------------------------------------------------------------------------- /examples/working/unscoped-function.ey: -------------------------------------------------------------------------------- 1 | < { deff }" > -- /abc deff 2 | 3 | { 1 /foo abc foo dump } * 4 | -------------------------------------------------------------------------------- /interpreter/ElymasAsm.pm: -------------------------------------------------------------------------------- 1 | package ElymasAsm; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Elymas; 7 | use ACME::Bare::Metal; 8 | 9 | sub constructBlock { 10 | my ($block, $size) = @_; 11 | 12 | my $scope; $scope = \{ 13 | 'base' => [$block, 'int', 'passive'], 14 | 'size' => [$size, 'int', 'passive'], 15 | 'free' => [sub { 16 | my ($data) = @_; 17 | 18 | ACME::Bare::Metal::deallocate($$scope->{'base'}->[0], $$scope->{'size'}->[0]); 19 | }, ['func', 'sys .asm .free'], 'active'], 20 | }; 21 | 22 | return $$scope; 23 | } 24 | 25 | our $asm = { 26 | 'alloc' => [sub { 27 | my ($data) = @_; 28 | 29 | my $size = popInt($data); 30 | my $block = ACME::Bare::Metal::allocate($size); 31 | 32 | push @$data, [constructBlock($block, $size), ['struct']]; 33 | }, ['func', 'sys .asm .alloc'], 'active'], 34 | 'allocAt' => [sub { 35 | my ($data) = @_; 36 | 37 | my $addr = popInt($data); 38 | my $size = popInt($data); 39 | my $block = ACME::Bare::Metal::allocateAt($size, $addr); 40 | 41 | push @$data, [constructBlock($block, $size), ['struct']]; 42 | }, ['func', 'sys .asm .alloc'], 'active'], 43 | 'poke' => [sub { 44 | my ($data, $scope) = @_; 45 | 46 | my $addr = popInt($data); 47 | my $value = popInt($data); 48 | 49 | ACME::Bare::Metal::poke($addr, $value); 50 | }, ['func', 'sys .asm .poke', ['int', 'int'], []], 'active'], 51 | 'peek' => [sub { 52 | my ($data, $scope) = @_; 53 | 54 | my $addr = popInt($data); 55 | my $value = ACME::Bare::Metal::peek($addr); 56 | 57 | push @$data, [$value, 'int']; 58 | }, ['func', 'sys .asm .peek', ['int'], ['int']], 'active'], 59 | 'execute' => [sub { 60 | my ($data, $scope) = @_; 61 | 62 | my $addr = popInt($data); 63 | 64 | ACME::Bare::Metal::execute($addr); 65 | }, ['func', 'sys .asm .execute'], 'active'], 66 | }; 67 | -------------------------------------------------------------------------------- /interpreter/ElymasLinux.pm: -------------------------------------------------------------------------------- 1 | package ElymasLinux; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Elymas; 7 | 8 | use POSIX (); 9 | 10 | our $linux = { 11 | 'open' => [sub { 12 | my ($data, $scope) = @_; 13 | 14 | my $mode = popInt($data); 15 | my $flags = popInt($data); 16 | my $pathname = popString($data); 17 | 18 | my $fd = POSIX::open($pathname, $flags, $mode); 19 | $fd = -1 unless defined $fd; 20 | 21 | push @$data, [$fd, 'int']; 22 | }, ['func', 'linux .open'], 'active'], 23 | 'close' => [sub { 24 | my ($data, $scope) = @_; 25 | 26 | my $fd = popInt($data); 27 | 28 | my $ret = POSIX::close($fd); 29 | $ret = -1 unless defined $ret; 30 | 31 | push @$data, [$ret, 'int']; 32 | }, ['func', 'linux .close'], 'active'], 33 | # 'read' => [sub { 34 | # my ($data, $scope) = @_; 35 | # 36 | # my $count = popInt($data); 37 | # my $buf = popArray($data); 38 | # my $fd = popInt($data); 39 | # 40 | # my $ret = POSIX::close($fd); 41 | # $ret = -1 unless defined $ret; 42 | # 43 | # push @$data, [$ret, 'int']; 44 | # }, ['func', 'linux .read'], 'active'], 45 | }; 46 | 47 | map { installIntConstant($_) } qw(O_RDONLY O_RDWR O_WRONLY); 48 | 49 | sub installIntConstant { 50 | my ($name) = @_; 51 | 52 | my $elymasName = $name; 53 | $elymasName =~ s/_//g; 54 | 55 | $linux->{$elymasName} = [${$POSIX::{$name}}, 'int', 'passive']; 56 | } 57 | 58 | 1; 59 | -------------------------------------------------------------------------------- /interpreter/ElymasSys.pm: -------------------------------------------------------------------------------- 1 | package ElymasSys; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Elymas; 7 | use ElymasAsm; 8 | use POSIX; 9 | 10 | my $rwmask = &POSIX::O_RDONLY | &POSIX::O_WRONLY | &POSIX::O_RDWR; 11 | 12 | sub osType { 13 | my $uname = qx(uname); 14 | chomp $uname; 15 | 16 | if($uname eq 'Linux') { 17 | return 'linux'; 18 | } elsif($uname eq 'FreeBSD') { 19 | return 'freebsd'; 20 | } else { 21 | die "Unknown uname output '$uname', cannot decide what ABI to use."; 22 | } 23 | } 24 | 25 | our $sys = { 26 | 'file' => [sub { 27 | my ($data, $scope) = @_; 28 | 29 | my $file = createFile(-1, &POSIX::O_RDONLY); 30 | push @$data, [$file, ['struct']]; 31 | }, ['func', 'sys .file'], 'active'], 32 | 'in' => [createFile(0, &POSIX::O_RDONLY), ['struct'], 'passive'], 33 | 'out' => [createFile(1, &POSIX::O_WRONLY), ['struct'], 'passive'], 34 | 'err' => [createFile(2, &POSIX::O_WRONLY), ['struct'], 'passive'], 35 | 'argv' => [[map { [$_, 'string'] } @ARGV[1 .. $#ARGV]], ['array', 'sys .argv', ['range', 0, $#ARGV - 1], ['string']], 'passive'], 36 | 'asm' => [$ElymasAsm::asm, ['struct'], 'passive'], 37 | osType() => [{ }, ['struct'], 'passive'], 38 | }; 39 | 40 | sub createFile { 41 | my ($fd, $flags) = @_; 42 | 43 | my $scope; 44 | $scope = \{ 45 | ' fd' => [$fd, 'int', 'passive'], 46 | ' flags' => [$flags, 'int', 'passive'], 47 | ' mode' => [0777, 'int', 'passive'], 48 | 'readonly' => [sub { 49 | $$scope->{' flags'}->[0] = ($$scope->{' flags'}->[0] & ~($rwmask)) | &POSIX::O_RDONLY; 50 | }, ['func', 'sys .file .readonly'], 'active'], 51 | 'writeonly' => [sub { 52 | $$scope->{' flags'}->[0] = ($$scope->{' flags'}->[0] & ~($rwmask)) | &POSIX::O_WRONLY; 53 | }, ['func', 'sys .file .readonly'], 'active'], 54 | 'readwrite' => [sub { 55 | $$scope->{' flags'}->[0] = ($$scope->{' flags'}->[0] & ~($rwmask)) | &POSIX::O_RDWR; 56 | }, ['func', 'sys .file .readonly'], 'active'], 57 | 'open' => [sub { 58 | my ($data) = @_; 59 | 60 | die "file already open" unless $$scope->{' fd'}->[0] == -1; 61 | 62 | my $path = popString($data); 63 | 64 | my $fd = POSIX::open($path, $$scope->{' flags'}->[0], $$scope->{' mode'}->[0]); 65 | die "cannot open $path: $!" unless defined $fd; 66 | 67 | $$scope->{' fd'}->[0] = $fd; 68 | }, ['func', 'sys .file .open'], 'active'], 69 | 'close' => [sub { 70 | die "file not open" if $$scope->{' fd'}->[0] == -1; 71 | 72 | my $ret = POSIX::close($$scope->{' fd'}->[0]); 73 | die "close failed: $!" unless defined $ret; 74 | 75 | $$scope->{' fd'}->[0] = -1; 76 | }, ['func', 'sys .file .close'], 'active'], 77 | 'read' => [sub { 78 | my ($data) = @_; 79 | 80 | die "file not open" if $$scope->{' fd'}->[0] == -1; 81 | 82 | my $count = popInt($data); 83 | 84 | my $buf; 85 | my $ret = POSIX::read($$scope->{' fd'}->[0], $buf, $count); 86 | die "read failed: $!" unless defined $ret; 87 | 88 | push @$data, [$buf, 'string']; 89 | }, ['func', 'sys .file .read'], 'active'], 90 | 'writeall' => [sub { 91 | my ($data) = @_; 92 | 93 | die "file not open" if $$scope->{' fd'}->[0] == -1; 94 | 95 | my $buf = popArray($data); 96 | $buf = join '', map { chr($_->[0]) } @$buf; 97 | 98 | while($buf) { 99 | my $ret = POSIX::write($$scope->{' fd'}->[0], $buf, length $buf); 100 | die "write failed: $!" unless defined $ret; 101 | $buf = substr($buf, $ret); 102 | } 103 | }, ['func', 'sys .file .writeall'], 'active'], 104 | 'write' => [sub { 105 | my ($data) = @_; 106 | 107 | die "file not open" if $$scope->{' fd'}->[0] == -1; 108 | 109 | my $buf = popString($data); 110 | 111 | while($buf) { 112 | my $ret = POSIX::write($$scope->{' fd'}->[0], $buf, length $buf); 113 | die "write failed: $!" unless defined $ret; 114 | $buf = substr($buf, $ret); 115 | } 116 | }, ['func', 'sys .file .writestr'], 'active'], 117 | }; 118 | 119 | return $$scope; 120 | } 121 | 122 | # sub installIntConstant { 123 | # my ($name) = @_; 124 | # 125 | # my $elymasName = $name; 126 | # $elymasName =~ s/_//g; 127 | # 128 | # $linux->{$elymasName} = [${$POSIX::{$name}}, 'int', 'passive']; 129 | # } 130 | 131 | 1; 132 | -------------------------------------------------------------------------------- /interpreter/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | 3 | test: 4 | for f in $$(ls ../examples/working); do \ 5 | printf "%20s: " $$f; \ 6 | echo Input | ( cd ../examples/working; ../../interpreter/elymas "$$f"; echo ) \ 7 | 2> "test/$$f.err.test" > "test/$$f.test"; \ 8 | if diff "test/$$f.test" "test/$$f.correct" && diff "test/$$f.err.test" "test/$$f.err.correct"; then \ 9 | echo "Success."; \ 10 | else \ 11 | echo "Failed."; \ 12 | fi \ 13 | done 14 | 15 | generate-test: 16 | mkdir -p test 17 | for f in $$(ls ../examples/working); do \ 18 | echo $$f; \ 19 | echo Input | ( cd ../examples/working; ../../interpreter/elymas "$$f"; echo ) \ 20 | 2> "test/$$f.err.correct" | tee "test/$$f.correct"; \ 21 | sleep 1; \ 22 | done 23 | 24 | generate-test-fast: 25 | mkdir -p test 26 | for f in $$(ls ../examples/working); do \ 27 | echo $$f; \ 28 | echo Input | ( cd ../examples/working; ../../interpreter/elymas "$$f"; echo ) \ 29 | 2> "test/$$f.err.correct" | tee "test/$$f.correct"; \ 30 | done 31 | -------------------------------------------------------------------------------- /interpreter/elymas: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | BEGIN { 7 | my $libPath = $0; 8 | $libPath =~ s!/?elymas$!!; 9 | push @INC, $libPath; 10 | } 11 | 12 | use Data::Dumper; 13 | # $Data::Dumper::Deparse = 1; 14 | 15 | use Elymas; 16 | use ElymasGlobal; 17 | 18 | executeFile($ARGV[0], $globalData, \$globalScope); 19 | -------------------------------------------------------------------------------- /support/elymas.vim: -------------------------------------------------------------------------------- 1 | syn clear 2 | syn case match 3 | 4 | hi link eyNonword Operator 5 | hi link eyEscapeSeq SpecialChar 6 | hi link eyControl Statement 7 | hi link eyMath Function 8 | hi link eyMacro Function 9 | hi link eyOther Function 10 | hi link eyNumber Constant 11 | hi link eyString Constant 12 | hi link eyAutoquoteWord Constant 13 | hi link eyModule Constant 14 | hi link eyComment Comment 15 | hi link eyWord Normal 16 | 17 | syn match eyNonword /[^a-zA-Z0-9 ]\+/ 18 | syn match eyWord /[a-zA-Z0-9]\+/ 19 | syn match eyAutoquoteWord /[a-zA-Z0-9][^ ]*/ contained 20 | syn match eyCombined /[^a-zA-Z0-9 ]\+[a-zA-Z0-9][^ ]*/ contains=eyNonWord,eyAutoquoteWord 21 | syn match eyNumber /[0-9]\+/ 22 | syn region eyString start=/"/ end=/"/ contains=eyEscapeSeq 23 | syn match eyEscapeSeq /\\["n\\']/ contained 24 | syn keyword eyControl rep include dump die each loop exe 25 | syn keyword eyMath regex range 26 | syn keyword eyMath sig len cat dearray dom keys 27 | syn keyword eyMath add sub mul div mod and nand or xor nxor nor band bnand bor bxor bnxor bnor 28 | syn keyword eyMath eq neq lt le gt ge gcd neg not bnot abs streq 29 | syn keyword eyOther quoted deff defv defq defvs deffs defvt defft defvst deffst defvc deffc defvd deffd defm defms defmt defmst defmc defmd 30 | syn keyword eyOther code sym blk 31 | syn keyword eyModule sys 32 | syn match eyComment /#.*$/ 33 | --------------------------------------------------------------------------------