197 Commits
v6.5 ... v9.0

Author SHA1 Message Date
ValKmjolnir
d567f5abf8 📝 update test/module_test.nas 2022-05-17 21:48:08 +08:00
ValKmjolnir
f8692f1e4e 📝 update test files 2022-05-17 18:22:24 +08:00
ValKmjolnir
712a047a43 🐛 now builtin_md5 uses unsigned char instead of char 2022-05-15 20:35:20 +08:00
ValKmjolnir
396d55a207 fix some warnings 2022-05-09 18:42:40 +08:00
ValKmjolnir
c5171c735a 💬 change code related to macros 'PRTHEX' 2022-05-08 19:43:27 +08:00
ValKmjolnir
07857d980c 📝 update test/utf8chk.nas 2022-05-07 17:18:29 +08:00
ValKmjolnir
51a1279110 add utf-8 identifier check in nasal_lexer & fix printf format at windows platform & add test file utf8chk.nas 2022-05-07 16:50:13 +08:00
ValKmjolnir
de262980cc 🎨 improve rawstr() and builtin_getcwd(..), change format output in nasal_vm::valinfo() 2022-05-07 02:22:49 +08:00
ValKmjolnir
23a5c1b1ad 🐛 bug fix 2022-05-06 20:58:02 +08:00
ValKmjolnir
fd8a148d0c bytecode info print and debugger will show the front 16 characters of strings whose length is greater than 16 2022-05-02 16:56:03 +08:00
ValKmjolnir
9c7f5f1a6e update test file diff.nas& add math.max math.min 2022-05-01 21:10:23 +08:00
ValKmjolnir
f049e1f9fb add test file diff.nas 2022-04-30 20:00:15 +08:00
ValKmjolnir
c4b7712e53 update README.md 2022-04-27 12:49:29 +08:00
ValKmjolnir
7417d5e635 change makefile 2022-04-26 22:53:35 +08:00
ValKmjolnir
785572634b change visual settings in -c/-dbg 2022-04-23 01:51:49 +08:00
ValKmjolnir
2dc8459cbf use effective way to check if file exists 2022-04-21 20:51:47 +08:00
ValKmjolnir
6e035d1951 add lib load code to automatically load lib.nas 2022-04-21 19:45:16 +08:00
ValKmjolnir
4f5fd3de33 op_addeq~op_lnkeq and op_addeqc~op_lnkeqc and op_meq operands now can do pop, this will decrease the frequency of calling op_pop 2022-04-17 17:20:18 +08:00
ValKmjolnir
fc25dd69e1 fix bug in codegen: foreach/forindex(id;vec/hash) may cause segmentation fault because of incorrect generated operand 2022-04-16 19:45:55 +08:00
ValKmjolnir
ca073499ae optimize codes 2022-04-13 19:08:06 +08:00
ValKmjolnir
022460755f optimize codes 2022-04-12 18:26:54 +08:00
ValKmjolnir
b6f174e869 update test/wavecollapse.nas 2022-04-10 16:47:27 +08:00
ValKmjolnir
7b160c4589 add test file wavecollapse.nas 2022-04-10 15:34:20 +08:00
ValKmjolnir
4503239731 change STACK_MAX_DEPTH to nasal_gc::stack_depth 2022-04-09 23:14:28 +08:00
ValKmjolnir
c12e812651 change test/md5compare.nas 2022-04-06 22:56:21 +08:00
ValKmjolnir
87cff700e8 change module/libmd5 to native function builtin_md5() in nasal_builtin.h 2022-04-06 22:30:49 +08:00
ValKmjolnir
bf5737ecfd add native function abort(), assert() 2022-04-06 21:25:20 +08:00
ValKmjolnir
651ae4ef77 add native function isa(object,class) 2022-04-05 22:33:55 +08:00
ValKmjolnir
e846e51175 add native function: srand, values, find. 2022-04-05 22:15:05 +08:00
ValKmjolnir
399b2f0ce9 bug fixed & add systime, finished vecindex 2022-04-04 19:08:48 +08:00
ValKmjolnir
aed5e27409 bug fix & optimize test code & add lib function: subvec, floor, abs, isfunc, isghost, isint, isnum, isscalar, isstr, isvec, vecindex(unfinished) 2022-04-04 18:38:25 +08:00
ValKmjolnir
a2b51fe212 optimize libmd5.nas & test/md5.nas 2022-04-03 18:10:00 +08:00
ValKmjolnir
92b684624d change module/makefile and test/md5compare.nas 2022-04-01 22:52:04 +08:00
ValKmjolnir
83a8632e8e update test/md5compare.nas & optimize test/md5.nas 2022-03-31 19:31:00 +08:00
ValKmjolnir
41b5304712 update test/md5compare.nas
and CAUTION: now the cpp&nas md5 program may not calculate strings including unicode
2022-03-30 21:42:30 +08:00
ValKmjolnir
c5a12ade5c update md5compare.nas 2022-03-29 22:54:17 +08:00
ValKmjolnir
7a939b417d fix bug in test/md5.nas & add test file md5compare.nas 2022-03-29 22:36:28 +08:00
ValKmjolnir
dd7740f1fd update test/md5.nas(still has bug) & add libmd5 in module(written in C++) 2022-03-28 17:14:11 +08:00
ValKmjolnir
617ad03d33 add math.pow 2022-03-27 16:14:55 +08:00
ValKmjolnir
b66ebbef4b fix bytecode output format bug 2022-03-27 13:10:35 +08:00
ValKmjolnir
7f22b25909 update README.md 2022-03-27 01:36:38 +08:00
ValKmjolnir
86f6296268 change opcode print format 2022-03-27 01:20:17 +08:00
ValKmjolnir
cf722fd98c fix bug: windows ps/cmd output unicode in bytecodes abnormally.
so we use the hex format to print them.
2022-03-23 22:54:07 +08:00
ValKmjolnir
1dd3fd445c add test/snake.nas 2022-03-20 22:08:11 +08:00
ValKmjolnir
27e25f84ec update main.cpp and bug fix 2022-03-20 18:28:45 +08:00
ValKmjolnir
e6457651d3 add unix.waitpid 2022-03-16 18:44:38 +08:00
ValKmjolnir
c4d52a88cd update docs & fix bug in nasal_builtin.h 2022-03-16 15:30:34 +08:00
ValKmjolnir
9bcad59e45 change enum obj_type to nasal_obj::obj_type 2022-03-15 22:51:14 +08:00
ValKmjolnir
9a099f66cb update docs 2022-03-14 20:29:49 +08:00
ValKmjolnir
b79d60fab5 add destructors for obj_file, obj_dylib, obj_dir & bug fix 2022-03-13 00:11:50 +08:00
ValKmjolnir
82e9e97a26 add destructor for obj_file & change arguments in test/tetris.nas 2022-03-12 23:37:16 +08:00
ValKmjolnir
6a1338bb23 update test/tetris.nas 2022-03-11 23:42:09 +08:00
ValKmjolnir
3b8a092f36 fix bug in test/json.nas 2022-03-11 15:26:38 +08:00
ValKmjolnir
3d86a32b12 update fully functional test/json.nas 2022-03-11 15:11:24 +08:00
ValKmjolnir
f26719e1d3 visual update 2022-03-10 16:05:49 +08:00
ValKmjolnir
e54ef9620f change nasal_ref value option functions' output types from pointers to references 2022-03-09 22:54:54 +08:00
ValKmjolnir
d8156e839b add unix.fork&unix.pipe(do not work on windows platform) 2022-03-09 19:03:12 +08:00
ValKmjolnir
61666d275d delete lstk&fstk, store local address and function on stack and in vm registers 2022-03-08 17:30:40 +08:00
ValKmjolnir
99f595e16f update num->string algorithm, now the to_string will output strings with no tailing zeros 2022-03-08 13:40:27 +08:00
ValKmjolnir
debe32b187 safer stl/module.nas & add stl/file.nas encapsulated from lib.nas/io 2022-03-06 15:17:39 +08:00
ValKmjolnir
ca9b8581b4 add module.nas to safely use dylib 2022-03-05 21:52:29 +08:00
ValKmjolnir
a0b341deb5 try fix bug 'use of undeclared identifier 'environ'' on MacOS 2022-03-05 19:24:33 +08:00
ValKmjolnir
d3df356299 add unix.environ() & use LPCWSTR in dylib.dlopen on Windows platform 2022-03-05 19:15:52 +08:00
ValKmjolnir
cd808a5e6d update detailed-info 2022-03-03 19:00:23 +08:00
ValKmjolnir
40f61a9dd4 fix bug of upval_state 2022-03-02 19:28:17 +08:00
ValKmjolnir
f312250d27 update 2022-03-01 14:36:05 +08:00
ValKmjolnir
3fac8aa665 fix bug in test/tetris.nas 2022-02-25 23:34:02 +08:00
ValKmjolnir
243aafd417 fix bug of -o not working. 2022-02-23 21:56:45 +08:00
ValKmjolnir
6bc03601d9 update test/tetris.nas 2022-02-23 01:09:31 +08:00
ValKmjolnir
f05acaecc7 fix bug in libkey and test/tetris.nas 2022-02-22 18:01:49 +08:00
ValKmjolnir
9456a903d7 finish tetris.nas 2022-02-21 17:10:13 +08:00
ValKmjolnir
984deed883 finish basic functions of tetris 2022-02-21 00:47:32 +08:00
ValKmjolnir
557cb2ebcf finish map drawing in test/tetris.nas 2022-02-20 17:58:13 +08:00
ValKmjolnir
9c055a9a23 add new third-lib libkey that includes function: kbhit,getch,nonblock 2022-02-19 16:55:54 +08:00
ValKmjolnir
13a09343e6 update README.md 2022-02-18 15:59:27 +08:00
ValKmjolnir
8c67e04cc4 update test file 2022-02-18 15:36:34 +08:00
ValKmjolnir
e77bb73a82 add special character \e. 2022-02-18 01:58:49 +08:00
ValKmjolnir
05fc5db337 change parameter name in native function split. 2022-02-17 23:34:58 +08:00
ValKmjolnir
a4738e8c7d delete operand op_nop 2022-02-16 23:27:22 +08:00
ValKmjolnir
5f6051e333 change tutorial's place in README.md 2022-02-15 23:42:17 +08:00
ValKmjolnir
51afe3dacd fixed bug when -O0 the program crashes with code 01.
add `nasal_err():error(0){}` in `nasal_err.h:47` as the constructor.
2022-02-14 17:40:19 +08:00
ValKmjolnir
0291908675 update README.md 2022-02-14 17:29:26 +08:00
ValKmjolnir
5fba784d05 add new gc type vm_upval 2022-02-13 22:40:54 +08:00
ValKmjolnir
9139e34c0b update README & bug fixed 2022-02-13 16:10:02 +08:00
ValKmjolnir
e7f503fae1 now local values are stored on stack. upvalue is generated when creating a new function in local scope.
may include some bugs inside. but all test files has passed the test so i decide to push it.
2022-02-12 23:12:30 +08:00
ValKmjolnir
980350d70a prepare for function-call optimization 2022-02-12 18:03:50 +08:00
ValKmjolnir
0ccd3c9bd0 update test/calc.nas & print function of nasal_vec/nasal_hash 2022-02-11 17:04:27 +08:00
ValKmjolnir
3e7ba4d774 little update 2022-02-10 22:20:18 +08:00
ValKmjolnir
a176022840 add notes in lib.nas & add runtime.gc() & add total instruction count in '-o'. 2022-02-09 15:53:09 +08:00
ValKmjolnir
24a1e39ad3 add garbage collector and memory allocator info. use '-d' to activate this function. 2022-02-08 23:40:52 +08:00
ValKmjolnir
a09c6ae2f9 update/optimize test files 2022-02-07 23:41:50 +08:00
ValKmjolnir
2a85e92d4a optimize test file & little update. 2022-02-06 19:55:45 +08:00
ValKmjolnir
92646840e4 reuse codes in nasal_vec::print and nasal_hash::print
now they all use nasal_ref::print
2022-02-05 23:55:56 +08:00
ValKmjolnir
c55ce758ed change increment arguments to a more efficiency level & change gc.nil, gc.one, gc.zero to constant nil, one, zero 2022-02-04 01:51:30 +08:00
ValKmjolnir
aa301aefc3 change increment argument in nasal_gc, because new vm doesn't need to alloc new objects frequently.
vm_str  2048 -> 512

vm_func 1024 -> 512

vm_vec  8192 -> 512
2022-02-03 22:43:51 +08:00
ValKmjolnir
d6d90ab7c8 change 'global' & 'local' in codegen to std::unordered_map & std::vector<std::unordered_map>> 2022-02-02 23:52:00 +08:00
ValKmjolnir
bf780514e6 add constant string calculation in optimizer 2022-02-01 21:20:36 +08:00
ValKmjolnir
eaa54035ff change name of enum:ast_hashmember->ast_pair, ast_new_iter->ast_iter
change ast_hashmember to ast_pair is because this type in fact is the same as std::pair<std::string,nasal_ref> in C++
2022-01-31 17:22:44 +08:00
ValKmjolnir
baa4f5a258 change error info of native function __builtin_import 2022-01-31 14:48:51 +08:00
ValKmjolnir
df24db5b58 optimize nasal_import::check_import 2022-01-30 23:26:30 +08:00
ValKmjolnir
4def93b4ad bug fixed in nasal_vec::print and nasal_hash::print
if vec's or hash's size is 0, a bug will occur because ++depth. now the ++depth has been put behind the size()
2022-01-29 19:51:43 +08:00
ValKmjolnir
0a407437a4 change native function num()
num now returns nil if the argument is not a number or numerable string.
2022-01-27 21:41:06 +08:00
ValKmjolnir
05ab4640da add notes of some native functions in lib.nas 2022-01-26 23:51:25 +08:00
ValKmjolnir
b92eb4b089 update README.md 2022-01-25 15:02:57 +08:00
ValKmjolnir
5778d1e38d update new test data 2022-01-24 15:19:27 +08:00
ValKmjolnir
479e5a2c52 fix errors in README.md 2022-01-22 22:19:14 +08:00
ValKmjolnir
2f455c52c1 fix error in README.md 2022-01-22 22:09:00 +08:00
ValKmjolnir
78c1f9b7a9 add contents in README.md 2022-01-22 22:05:42 +08:00
ValKmjolnir
c68b4c5947 add new option -op & --optimize to use optimizer | delete bytecode op_pone & op_pzero 2022-01-22 13:37:49 +08:00
ValKmjolnir
40344455e6 add optimizer
optimizer now does one work: calculate const number before generating bytecode
2022-01-22 00:41:08 +08:00
ValKmjolnir
630c99c39a optimize codes 2022-01-16 22:48:00 +08:00
ValKmjolnir
46716620e3 add test file 'turingmachine.nas' & change output format of ast & bug fixed 2021-12-28 20:23:47 +08:00
ValKmjolnir
70a43c2f03 bug fixed 2021-12-25 15:56:08 +08:00
ValKmjolnir
1923fc74e4 update README.md 2021-12-23 21:46:53 +08:00
ValKmjolnir
f0ae63bce5 lexer,parser,import,codegen use the same error module. 2021-12-23 21:15:50 +08:00
ValKmjolnir
30650bb64f update error info (except parser)
prepare for nasal_err module
2021-12-23 14:09:54 +08:00
ValKmjolnir
d87aef82b7 debug info now shows both source code and bytecode 2021-12-21 19:57:23 +08:00
ValKmjolnir
e79d1eb8a4 add debugger function: break point & next step 2021-12-21 15:27:38 +08:00
ValKmjolnir
189d49fa4a add debugger framework
with function:backtrace,run,help,show global/local/upvalue,exit
2021-12-20 21:33:22 +08:00
Li Haokun
6a543f2aa7 Merge pull request #7 from sidi762/master
Update c-cpp.yml to solve failures
2021-12-17 00:31:16 +08:00
ValKmjolnir
c27c5b70ee little update 2021-12-16 23:53:13 +08:00
Sidi Liang
0a246d2fc7 Merge branch 'ValKmjolnir:master' into master 2021-12-13 08:49:45 +08:00
Sidi Liang
0956a08bec Update c-cpp.yml 2021-12-13 08:46:20 +08:00
ValKmjolnir
5a80258d20 bug fixed & add os.platform 2021-12-08 18:46:32 +08:00
Li Haokun
85bb502191 Merge pull request #6 from sidi762/master
New Github Action for nightly builds on macOS
2021-12-07 10:37:39 +08:00
Sidi Liang
ead49a657e Change the asset name to 'nasal' 2021-12-06 23:00:25 +08:00
Sidi Liang
df5be35af8 Attempt to make nightly builds for macOS 2021-12-06 22:55:18 +08:00
Sidi Liang
19d5952210 Update c-cpp.yml 2021-12-06 22:47:37 +08:00
Sidi Liang
afd87da5e7 Try out GitHub Actions 2021-12-06 22:36:08 +08:00
ValKmjolnir
9861ecd03e add dylib.dlopen dylib.dlsym dylib.dlclose dylib.dlcall
now you could add your own modules into nasal without changing the source code!
2021-12-03 19:31:03 +08:00
ValKmjolnir
aa191a9feb delete ret stack/ add math.lg
now return address is stored on value stack
2021-12-02 22:23:22 +08:00
ValKmjolnir
b8ef3cf6b6 delete op_cntpop & counter stack
now the iterator will be type vm_cnt and be stored on value stack.
2021-11-25 18:13:31 +08:00
ValKmjolnir
0a8655eb4d fixed bug of in_foreach and in_forindex 2021-11-22 14:24:28 +08:00
ValKmjolnir
52b49edbcf add unix.isdir and unix.isfile 2021-11-15 22:47:52 +08:00
ValKmjolnir
6a35c58df4 2 bugs fixed:
empty string will be true in conditional expressions,but now it is false(and string that is not empty and is not numerable will be true)

foreach(var i;func(){return []}()); will cause sigsegv because codegen generates error op_pop and op_cntpop,now the counter in_foreach and in_forindex change after generating
foreach/forindex expression before block generation.
2021-11-14 23:05:34 +08:00
ValKmjolnir
cd08b2d1bb change code structure 2021-11-02 22:44:42 +08:00
ValKmjolnir
f8e2918561 add unix.opendir unix.readdir unix.closedir 2021-10-31 23:11:04 +08:00
ValKmjolnir
e4ea34db51 add unix.time unix.chdir unix.sleep unix.getcwd unix.getenv 2021-10-29 19:52:49 +08:00
ValKmjolnir
4bfce37f40 add bits lib 2021-10-28 21:49:08 +08:00
ValKmjolnir
fd0d836c03 add io lib & bug fixed 2021-10-27 23:05:25 +08:00
ValKmjolnir
183446d32a bug fixed 2021-10-26 22:34:02 +08:00
ValKmjolnir
540aeb73f4 optimize nasal_ast and fix bug in opr_slc2 2021-10-20 20:54:23 +08:00
ValKmjolnir
4f0acc4d63 fix dynamic para error 2021-10-18 22:05:31 +08:00
ValKmjolnir
56280db2c7 fix sigsegv error 2021-10-18 21:50:25 +08:00
ValKmjolnir
885b57cd52 add upvalue info into detail crash info 2021-10-18 19:59:41 +08:00
ValKmjolnir
bbee31ea55 add detail crash info 2021-10-17 22:57:45 +08:00
ValKmjolnir
1bfa7d2638 update 2021-10-16 23:36:43 +08:00
ValKmjolnir
d4a9412947 optimize code structure 2021-10-16 21:08:57 +08:00
ValKmjolnir
1b240b293e update variable name in nasal_lexer 2021-10-16 14:07:55 +08:00
ValKmjolnir
e41f728589 update 2021-10-15 22:21:57 +08:00
ValKmjolnir
577546763f change function name and cli format 2021-10-14 23:22:28 +08:00
ValKmjolnir
58ea303202 complete simple tutorial 2021-10-14 13:42:07 +08:00
ValKmjolnir
818685c48d change output format of information of bytecodes 2021-10-13 22:59:15 +08:00
ValKmjolnir
5d13261516 optimize source code 2021-10-12 18:26:10 +08:00
ValKmjolnir
56289b5d22 fully functional closure & add benchmark 2021-10-10 14:29:23 +08:00
ValKmjolnir
1733ac0573 vm_nil,vm_num changed to no-gcobject 2021-10-08 23:18:26 +08:00
ValKmjolnir
d71b4f09e2 prepare for version 8.0 2021-10-08 15:32:18 +08:00
ValKmjolnir
13d40e886e update 2021-09-25 23:25:31 +08:00
Li Haokun
618ce59233 bad access bug fixed 2021-09-13 19:55:03 +08:00
Li Haokun
071d8bd1ce update 2021-09-10 19:13:42 +08:00
Li Haokun
c498d5c8c4 add fg constants & change int(), num() 2021-09-02 19:10:49 +08:00
Li Haokun
11971267dc add math.nan math.inf 2021-09-01 19:15:32 +08:00
Li Haokun
418531a44a add result.nas 2021-09-01 19:14:03 +08:00
Li Haokun
59dc0d1423 add isnan 2021-08-27 17:43:01 +08:00
Li Haokun
385f0af17e nothing changed 2021-08-24 19:34:52 +08:00
Li Haokun
ef9b781961 security holes fixed 2021-08-19 17:54:36 +08:00
ValKmjolnir
80cc8e9db7 closure bugs fixed 2021-08-17 01:18:35 +08:00
Li Haokun
b2be386be8 update hexdump.nas 2021-08-13 15:10:20 +08:00
Li Haokun
e4c598cae6 add hexdump.nas 2021-08-12 20:01:51 +08:00
Li Haokun
5fe6681b0d update lexer 2021-08-12 19:00:17 +08:00
Li Haokun
35fc848672 fully functional closure 2021-08-11 14:54:17 +08:00
Li Haokun
e3f3bd7387 update readme 2021-08-10 17:55:49 +08:00
ValKmjolnir
638ec1c3a3 use same indentation 2021-08-09 21:30:18 +08:00
Li Haokun
90ac468aa9 update 2021-08-09 19:13:39 +08:00
ValKmjolnir
65dfef0a33 update 2021-08-09 01:02:27 +08:00
Li Haokun
76a2548e95 update 2021-08-06 18:57:06 +08:00
Li Haokun
40b690b67b update 2021-08-05 19:02:41 +08:00
Li Haokun
2b17f3d702 update debug info 2021-08-04 14:32:56 +08:00
ValKmjolnir
5b6c78783e update README 2021-08-04 00:03:49 +08:00
Li Haokun
fa618eb97f variables can be used before definition
change program to command line
change trace back info
change print function of nasal_vec and nasal_hash
2021-08-03 18:55:11 +08:00
ValKmjolnir
d0616ef028 update 2021-08-01 22:37:42 +08:00
ValKmjolnir
91771297d3 add test file 2021-08-01 22:34:02 +08:00
ValKmjolnir
4e1a3c5f2d syntax bug fixed
syntax like:
var f=func(){}
(var a,b,c)=(1,2,3);
will be incorrectly recognized like:
var f=func(){}(var a,b,c)

this bug is fixed now.
2021-08-01 02:11:27 +08:00
ValKmjolnir
df634cb1b2 update readme:difference between this and andy's interpreter 2021-08-01 01:54:14 +08:00
Li Haokun
aa797142d1 update parser
one bug found, waiting to be fixed
2021-07-28 18:22:40 +08:00
Li Haokun
816be43a98 update 2021-07-24 19:59:56 +08:00
Li Haokun
9ebabfe737 fixed bug in nasal_parse 2021-07-21 17:38:11 +08:00
ValKmjolnir
884b56ac09 bug fixed & raw string print 2021-07-21 00:20:25 +08:00
Li Haokun
61677101e4 show vm stack top's info when error occurs 2021-07-20 19:21:05 +08:00
Li Haokun
7a93f5b89b update 2021-07-19 17:04:45 +08:00
Li Haokun
9fe7a86a3b add trace back info 2021-07-16 17:18:13 +08:00
ValKmjolnir
9da029b8fe prepare for debugger 2021-07-16 02:17:53 +08:00
ValKmjolnir
8b8e72c879 update 2021-07-14 01:24:15 +08:00
ValKmjolnir
590c595522 delete slice_stack 2021-07-07 14:46:46 +08:00
ValKmjolnir
57d6bcdc52 add const compare instructions 2021-07-03 15:22:23 +08:00
ValKmjolnir
0b2fe61e6e add instruction & changes in codegen
add some instructions that execute const values.
the first symbol called in assignment will use op_load instead of op_meq,op_pop to assign.
2021-06-29 17:18:05 +08:00
ValKmjolnir
706659ba3d change instruction dispatch to computed-goto
bug fixed
prepare for version 7.0
2021-06-26 14:53:10 +08:00
74 changed files with 15968 additions and 5072 deletions

34
.github/workflows/c-cpp.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: C/C++ CI
on:
schedule:
- cron: "0 16 * * *"
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: make
run: make
- name: Release file
# You may pin to the exact commit or the version.
# uses: djnicholson/release-action@e9a535b3eced09c460e07a84118fb74ae9b53236
uses: marvinpinto/action-automatic-releases@v1.2.1
with:
# GitHub auth token
repo_token: ${{ secrets.GITHUB_TOKEN }}
# Name of Release to add file to
title: macOS Nightly build
# Name of the tag for the release (will be associated with current branch)
automatic_release_tag: next
# File to release
files: nasal

4
.gitignore vendored
View File

@@ -30,3 +30,7 @@
*.exe
*.out
*.app
nasal
.vscode
dump

1827
README.md

File diff suppressed because it is too large Load Diff

527
lib.nas
View File

@@ -1,144 +1,469 @@
var import=func(filename)
{
# lib.nas
# import is used to link another file, this lib function will do nothing.
# because nasal_import will recognize this and link files before generating bytecode.
var import=func(filename){
return __builtin_import(filename);
}
var print=func(elems...)
{
# print is used to print all things in nasal, try and see how it works.
# this function uses std::cout/printf to output logs.
var print=func(elems...){
return __builtin_print(elems);
};
var println=func(elems...)
{
}
# append is used to add values into a vector.
var append=func(vec,elems...){
return __builtin_append(vec,elems);
}
# setsize is used to change the size of vector.
# if the size is larger than before,
# this function will fill vm_nil into uninitialized space.
var setsize=func(vec,size){
return __builtin_setsize(vec,size);
}
# system has the same use in C.
var system=func(str){
return __builtin_system(str);
}
# input uses std::cin and returns what we input.
var input=func(){
return __builtin_input();
}
# split a string by separator for example:
# split("ll","hello world") -> ["he","o world"]
# this function will return a vector.
var split=func(separator,str){
return __builtin_split(separator,str);
}
# rand has the same function as the rand in C
# if seed is nil, it will return the random number.
# if seed is not nil, it will be initialized by this seed.
var rand=func(seed=nil){
return __builtin_rand(seed);
}
# id will return the pointer of an gc-object.
# if this object is not managed by gc, it will return 0.
var id=func(object){
return __builtin_id(object);
}
# int will get the integer of input number.
# but carefully use it, because int has range between -2147483648~2147483647
var int=func(val){
return __builtin_int(val);
}
# floor will get the integral number of input argument
# which is less than or equal to this argument
var floor=func(val){
return __builtin_floor(val);
}
# abort using std::abort
var abort=func(){
__builtin_abort();
}
# abs gets absolute number.
var abs=func(n){
return n>0?n:-n;
}
# num will change all the other types into number.
# mostly used to change a numerable string.
var num=func(val){
return __builtin_num(val);
}
# pop used to pop the last element in a vector.
# this function will return the value that poped if vector has element(s).
# if the vector is empty, it will return nil.
var pop=func(vec){
return __builtin_pop(vec);
}
# str is used to change number into string.
var str=func(num){
return __builtin_str(num);
}
# size can get the size of a string/vector/hashmap.
# in fact it can also get the size of number, and the result is the number itself.
# so don't do useless things, though it really works.
var size=func(object){
return __builtin_size(object);
}
# contains is used to check if a key exists in a hashmap/dict.
var contains=func(hash,key){
return __builtin_contains(hash,key);
}
# delete is used to delete a pair in a hashmap/dict by key.
var delete=func(hash,key){
return __builtin_delete(hash,key);
}
# keys is used to get all keys in a hashmap/dict.
# this function will return a vector.
var keys=func(hash){
return __builtin_keys(hash);
}
# time has the same function in C.
var time=func(begin){
return __builtin_time(begin);
}
var systime=func(){
return time(0);
}
# die is a special native function.
# use it at where you want the program to crash immediately.
var die=func(str){
return __builtin_die(str);
}
# find will give the first position of the needle in haystack
var find=func(needle,haystack){
return __builtin_find(needle,haystack);
}
# typeof is used to get the type of an object.
# this function returns a string.
var typeof=func(object){
return __builtin_type(object);
}
# subvec is used to get part of a vector
var subvec=func(vec,begin,length=nil){
return vec[begin:(length==nil?nil:begin+length-1)];
}
# substr will get the sub-string.
# it gets the string, the begin index and sub-string's length as arguments.
var substr=func(str,begin,len){
return __builtin_substr(str,begin,len);
}
# streq is used to compare if two strings are the same.
var streq=func(a,b){
return __builtin_streq(a,b);
}
# left is used to get the sub-string like substr.
# but the begin index is 0.
var left=func(str,len){
return __builtin_left(str,len);
}
# right i used to get the sub-string like substr.
# but the begin index is strlen-len.
var right=func(str,len){
return __builtin_right(str,len);
}
# cmp is used to compare two strings.
# normal string will not be correctly compared by operators < > <= >=
# because these operators will turn strings into numbers then compare.
var cmp=func(a,b){
return __builtin_cmp(a,b);
}
# chr is used to get the character by ascii-number.
# for example chr(65) -> 'A'
var chr=func(code){
return __builtin_chr(code);
}
# mut is used to change unmutable strings to mutable.
var mut=func(str){
return str~"";
}
# srand wraps up rand, using time(0) as the seed.
var srand=func(){
rand(time(0));
return 0;
}
# values() gets all values in a hash.
var values=func(hash){
return __builtin_values(hash);
}
# println has the same function as print.
# but it will output a '\n' after using print.
var println=func(elems...){
__builtin_print(elems);
elems=['\n'];
return __builtin_print(elems);
}
var append=func(vec,elems...)
{
return __builtin_append(vec,elems);
var isfunc=func(f){
return typeof(f)=="func";
}
var setsize=func(vec,size)
{
return __builtin_setsize(vec,size);
var isghost=func(g){
die("this runtime has no ghost object");
return 0;
}
var system=func(str)
{
return __builtin_system(str);
var ishash=func(h){
return typeof(h)=="hash";
}
var input=func()
{
return __builtin_input();
var isint=func(x){
return x==floor(x);
}
var sleep=func(duration)
{
return __builtin_sleep(duration);
var isnum=func(x){
return typeof(x)=="num" or !math.isnan(num(x));
}
var split=func(deli,str)
{
return __builtin_split(deli,str);
var isscalar=func(s){
var t=typeof(s);
return (t=="num" or t=="str")?1:0;
}
var rand=func(seed=nil)
{
return __builtin_rand(seed);
var isstr=func(s){
return typeof(s)=="str";
}
var id=func(object)
{
return __builtin_id(object);
var isvec=func(v){
return typeof(v)=="vec";
}
var int=func(val)
{
return __builtin_int(val);
# get the index of val in the vec
var vecindex=func(vec,val){
forindex(var i;vec)
if(val==vec[i])
return i;
return nil;
}
var num=func(val)
{
return __builtin_num(val);
# check if the object is an instance of the class
var isa=func(object,class){
if(!contains(object,"parents") or typeof(object.parents)!="vec")
return 0;
foreach(var elem;object.parents)
if(elem==class)
return 1;
return 0;
}
var pop=func(vec)
{
return __builtin_pop(vec);
# assert aborts when condition is not true
var assert=func(condition,message="assertion failed!"){
if(condition)
return 1;
die(message);
}
var str=func(num)
{
return __builtin_str(num);
}
var size=func(object)
{
return __builtin_size(object);
}
var contains=func(hash,key)
{
return __builtin_contains(hash,key);
}
var delete=func(hash,key)
{
return __builtin_delete(hash,key);
}
var keys=func(hash)
{
return __builtin_keys(hash);
}
var time=func(begin_time)
{
return __builtin_time(begin_time);
}
var die=func(str)
{
return __builtin_die(str);
}
var typeof=func(object)
{
return __builtin_type(object);
}
var substr=func(str,begin,len)
{
return __builtin_substr(str,begin,len);
}
var streq=func(a,b)
{
return __builtin_streq(a,b);
}
var left=func(str,len)
{
return __builtin_left(str,len);
}
var right=func(str,len)
{
return __builtin_right(str,len);
}
var cmp=func(a,b)
{
return __builtin_cmp(a,b);
}
var chr=func(code)
{
return __builtin_chr(code);
# md5
var md5=func(str){
return __builtin_md5(str);
}
var io=
{
fin: func(filename){return __builtin_fin(filename);},
fout:func(filename,str){return __builtin_fout(filename,str);}
SEEK_SET:0,
SEEK_CUR:1,
SEEK_END:2,
# get content of a file by filename. returns a string.
fin: func(filename){return __builtin_fin(filename);},
# input a string as the content of a file.
fout: func(filename,str){return __builtin_fout(filename,str);},
# same as C fopen. open file and get the FILE*.
open: func(filename,mode="r"){return __builtin_open(filename,mode);},
# same as C fclose. close file by FILE*.
close: func(filehandle){return __builtin_close(filehandle);},
# same as C fread. read file by FILE*.
# caution: buf must be a mutable string.use mut("") to get an empty mutable string.
read: func(filehandle,buf,len){return __builtin_read(filehandle,buf,len);},
# same as C fwrite. write file by FILE*.
write: func(filehandle,str){return __builtin_write(filehandle,str);},
# same as C fseek. seek place by FILE*.
seek: func(filehandle,pos,whence){return __builtin_seek(filehandle,pos,whence);},
# same as C ftell.
tell: func(filehandle){return __builtin_tell(filehandle);},
# read file by lines. use FILE*.
# get nil if EOF
readln:func(filehandle){return __builtin_readln(filehandle);},
# same as C stat.
stat: func(filename){return __builtin_stat(filename);},
# same as C feof. check if FILE* gets the end of file(EOF).
eof: func(filehandle){return __builtin_eof(filehandle);}
};
# get file status. using data from io.stat
var fstat=func(filename){
var s=io.stat(filename);
return {
st_dev: s[0],
st_ino: s[1],
st_mode: s[2],
st_nlink:s[3],
st_uid: s[4],
st_gid: s[5],
st_rdev: s[6],
st_size: s[7],
st_atime:s[8],
st_mtime:s[9],
st_ctime:s[10]
};
}
# functions that do bitwise calculation.
# carefully use it, all the calculations are based on integer.
var bits=
{
# xor
bitxor: func(a,b){return __builtin_xor(a,b); },
# and
bitand: func(a,b){return __builtin_and(a,b); },
# or
bitor: func(a,b){return __builtin_or(a,b); },
# nand
bitnand: func(a,b){return __builtin_nand(a,b);},
bitnot: func(a) {return __builtin_not(a); }
# not
bitnot: func(a) {return __builtin_not(a); },
# get bit data from a special string. for example:
# bits.fld(s,0,3);
# if s stores 10100010(162)
# will get 101(5).
fld: func(str,startbit,len){return __builtin_fld;},
# get sign-extended data from a special string. for example:
# bits.sfld(s,0,3);
# if s stores 10100010(162)
# will get 101(5) then this will be signed extended to
# 11111101(-3).
sfld: func(str,startbit,len){return __builtin_sfld;},
# set value into a special string to store it. little-endian, for example:
# bits.setfld(s,0,8,69);
# set 01000101(69) to string will get this:
# 10100010(162)
# so s[0]=162.
setfld: func(str,startbit,len,val){return __builtin_setfld;},
# get a special string filled by '\0' to use in setfld.
buf: func(len){return __builtin_buf;}
};
# mostly used math functions and special constants, you know.
var math=
{
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
inf: 1/0,
nan: 0/0,
abs: func(x) {return x>0?x:-x; },
floor: func(x) {return __builtin_floor(x); },
pow: func(x,y){return __builtin_pow(x,y); },
sin: func(x) {return __builtin_sin(x); },
cos: func(x) {return __builtin_cos(x); },
tan: func(x) {return __builtin_tan(x); },
exp: func(x) {return __builtin_exp(x); },
exp: func(x) {return __builtin_exp(x); },
lg: func(x) {return __builtin_lg(x); },
ln: func(x) {return __builtin_ln(x); },
sqrt: func(x) {return __builtin_sqrt(x); },
atan2: func(x,y){return __builtin_atan2(x,y);}
atan2: func(x,y){return __builtin_atan2(x,y);},
isnan: func(x) {return __builtin_isnan(x); },
max: func(x,y){return x>y?x:y; },
min: func(x,y){return x<y?x:y; }
};
var D2R=math.pi/180;
var unix=
{
pipe: func(){return __builtin_pipe;},
fork: func(){return __builtin_fork;},
dup2: func(fd0,fd1){die("not supported yet");},
exec: func(filename,argv,envp){die("not supported yet");},
waitpid: func(pid,nohang=0){return __builtin_waitpid;},
isdir: func(path){return bits.bitand(io.stat(path)[2],0x4000);}, # S_IFDIR 0x4000
isfile: func(path){return bits.bitand(io.stat(path)[2],0x8000);}, # S_IFREG 0x8000
opendir: func(path){return __builtin_opendir;},
readdir: func(handle){return __builtin_readdir;},
closedir: func(handle){return __builtin_closedir;},
time: func(){return time(0);},
sleep: func(secs){return __builtin_sleep(secs);},
chdir: func(path){return __builtin_chdir(path);},
environ: func(){return __builtin_environ();},
getcwd: func(){return __builtin_getcwd();},
getenv: func(envvar){return __builtin_getenv(envvar);}
};
# dylib is the core hashmap for developers to load their own library.
# for safe using dynamic library, you could use 'module' in stl/module.nas
var dylib=
{
# open dynamic lib.
dlopen: func(libname){return __builtin_dlopen;},
# load symbol from an open dynamic lib.
dlsym: func(lib,sym){return __builtin_dlsym; },
# close dynamic lib, this operation will make all the symbols loaded from it invalid.
dlclose: func(lib){return __builtin_dlclose; },
# call the loaded symbol.
dlcall: func(funcptr,args...){return __builtin_dlcall}
};
# os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported.
var os=
{
# get a string that tell which os it runs on.
platform: func(){return __builtin_platform;}
};
# runtime gives us some functions that we could manage it manually.
var runtime=
{
# do garbage collection manually.
# carefully use it because using it frequently may make program running slower.
gc: func(){return __builtin_gc;}
};
# important global constants
var D2R=math.pi/180;
var FPS2KT=0.5925;
var FT2M=0.3048;
var GAL2L=3.7854;
var IN2M=0.0254;
var KG2LB=2.2046;
var KT2FPS=1.6878;
var KT2MPS=0.5144;
var L2GAL=0.2642;
var LB2KG=0.4536;
var M2FT=3.2808;
var M2IN=39.3701;
var M2NM=0.00054;
var MPS2KT=1.9438;
var NM2M=1852;
var R2D=180/math.pi;
# functions that not supported in this runtime:
var bind=func(function,locals,outer_scope=nil){
die("this runtime does not support bind");
}
var call=func(function,args=nil,_me=nil,locals=nil,error=nil){
die("this runtime does not support call");
}
var caller=func(level=1){
die("this runtime does not support caller");
}
var closure=func(function,level=1){
die("this runtime uses \"vm_upval\" instead of \"vm_hash\" as the closure");
}
var compile=func(code,filename="<compile>"){
die("this runtime uses static code generator");
}

327
main.cpp
View File

@@ -1,173 +1,156 @@
#include "nasal.h"
void help_interact()
{
std::cout
<<">> [ ] input a file name to execute. \n"
<<">> [help ] show help. \n"
<<">> [clear] clear the screen. \n"
<<">> [lex ] view tokens. \n"
<<">> [ast ] view abstract syntax tree. \n"
<<">> [code ] view byte code. \n"
<<">> [exec ] execute program on bytecode vm.\n"
<<">> [logo ] print logo of nasal . \n"
<<">> [exit ] quit nasal interpreter. \n";
return;
}
void help_cmd()
{
std::cout
#ifdef _WIN32
<<"use command \'chcp 65001\' if want to use unicode.\n"
#endif
<<"nasal | use interactive interpreter.\n"
<<"nasal -h -help | get help.\n"
<<"nasal -v -version | get version of nasal interpreter.\n"
<<"nasal filename | execute script file.\n";
return;
}
void info()
{
std::cout
<<">> Nasal interpreter ver 6.5.\n"
<<">> Thanks to https://github.com/andyross/nasal\n"
<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n"
<<">> Code: https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language\n"
<<">> Input \"help\" to get help .\n";
return;
}
void logo()
{
std::cout
<<" __ _ \n"
<<" /\\ \\ \\__ _ ___ __ _| | \n"
<<" / \\/ / _` / __|/ _` | | \n"
<<" / /\\ / (_| \\__ \\ (_| | | \n"
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n";
return;
}
void die(const char* stage,std::string& filename)
{
std::cout<<">> ["<<stage<<"] in <\""<<filename<<"\">: error(s) occurred,stop.\n";
return;
}
void execute(std::string& file,std::string& command)
{
nasal_lexer lexer;
nasal_parse parse;
nasal_import import;
nasal_codegen codegen;
nasal_vm vm;
lexer.openfile(file);
lexer.scanner();
if(lexer.get_error())
{
die("lexer",file);
return;
}
if(command=="lex")
{
lexer.print_token();
return;
}
parse.set_toklist(lexer.get_token_list());
lexer.get_token_list().clear();
parse.main_process();
if(parse.get_error())
{
die("parse",file);
return;
}
if(command=="ast")
{
parse.get_root().print_ast(0);
return;
}
import.link(parse.get_root());
parse.get_root().clear();
if(import.get_error())
{
die("import",file);
return;
}
codegen.main_progress(import.get_root());
if(codegen.get_error())
{
die("codegen",file);
return;
}
if(command=="code")
{
codegen.print_byte_code();
return;
}
vm.init(
codegen.get_str_table(),
codegen.get_num_table(),
codegen.get_exec_code()
);
vm.run();
vm.clear();
return;
}
void interact()
{
#ifdef _WIN32
// use chcp 65001 to use unicode io
system("chcp 65001");
#endif
std::string command,file="null";
logo();
info();
while(1)
{
std::cout<<">> ";
std::cin>>command;
if(command=="help")
help_interact();
else if(command=="clear")
{
#ifdef _WIN32
system("cls");
#else
int rs=system("clear");
#endif
}
else if(command=="logo")
logo();
else if(command=="exit")
return;
else if(command=="lex" || command=="ast" || command=="code" || command=="exec")
execute(file,command);
else
file=command;
}
}
int main(int argc,const char* argv[])
{
std::string command,file="null";
if(argc==1)
interact();
else if(argc==2 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"-version")))
{
logo();
std::cout<<"Nasal interpreter ver 6.5\n";
}
else if(argc==2 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"-help")))
help_cmd();
else if(argc==2 && argv[1][0]!='-')
{
file=argv[1];
command="exec";
execute(file,command);
return 0;
}
else
{
std::cout
<<"invalid command.\n"
<<"use nasal -h to get help.\n";
}
return 0;
#include "nasal.h"
const uint32_t VM_LEXINFO =0x01;
const uint32_t VM_ASTINFO =0x02;
const uint32_t VM_CODEINFO =0x04;
const uint32_t VM_EXECTIME =0x08;
const uint32_t VM_OPCALLNUM=0x10;
const uint32_t VM_EXEC =0x20;
const uint32_t VM_DBGINFO =0x40;
const uint32_t VM_DEBUG =0x80;
const uint32_t VM_OPTIMIZE =0x100;
void help()
{
std::cout
#ifdef _WIN32
<<"use command <chcp 65001> if want to use unicode.\n"
#endif
<<"nasal <option>\n"
<<"option:\n"
<<" -h, --help | get help.\n"
<<" -v, --version | get version of nasal interpreter.\n\n"
<<"nasal <file>\n"
<<"file:\n"
<<" input file name to execute script file.\n\n"
<<"nasal [options...] <file>\n"
<<"option:\n"
<<" -l, --lex | view token info.\n"
<<" -a, --ast | view abstract syntax tree.\n"
<<" -c, --code | view bytecode.\n"
<<" -e, --exec | execute.\n"
<<" -t, --time | execute and get the running time.\n"
<<" -o, --opcnt | execute and count used operands.\n"
<<" -d, --detail | execute and get detail crash info.\n"
<<" | get garbage collector info if didn't crash.\n"
<<" -op, --optimize| use optimizer(beta).\n"
<<" | if want to use -op and run, please use -op -e/-t/-o/-d.\n"
<<" -dbg, --debug | debug mode (this will ignore -t -o -d -e).\n"
<<"file:\n"
<<" input file name to execute script file.\n";
}
void logo()
{
std::cout
<<" __ _\n"
<<" /\\ \\ \\__ _ ___ __ _| |\n"
<<" / \\/ / _` / __|/ _` | |\n"
<<" / /\\ / (_| \\__ \\ (_| | |\n"
<<" \\_\\ \\/ \\__,_|___/\\__,_|_|\n"
<<"nasal ver : "<<__nasver<<"\n"
<<"c++ std : "<<__cplusplus<<"\n"
<<"thanks to : https://github.com/andyross/nasal\n"
<<"code repo : https://github.com/ValKmjolnir/Nasal-Interpreter\n"
<<"code repo : https://gitee.com/valkmjolnir/Nasal-Interpreter\n"
<<"lang info : http://wiki.flightgear.org/Nasal_scripting_language\n"
<<"input <nasal -h> to get help .\n";
}
void err()
{
std::cout
<<"invalid argument(s).\n"
<<"use <nasal -h> to get help.\n";
std::exit(1);
}
void execute(const std::string& file,const uint32_t cmd)
{
// front end use the same error module
nasal_err nerr;
nasal_lexer lexer(nerr);
nasal_parse parse(nerr);
nasal_import linker(nerr);
nasal_codegen gen(nerr);
// back end
nasal_vm vm;
// lexer scans file to get tokens
lexer.scan(file);
if(cmd&VM_LEXINFO)
lexer.print();
// parser gets lexer's token list to compile
parse.compile(lexer);
// linker gets parser's ast and load import files to this ast
linker.link(parse,file);
// optimizer does simple optimization on ast
if(cmd&VM_OPTIMIZE)
optimize(parse.ast());
if(cmd&VM_ASTINFO)
parse.print();
// code generator gets parser's ast and linker's import file list to generate code
gen.compile(parse,linker);
if(cmd&VM_CODEINFO)
gen.print();
// run bytecode
if(cmd&VM_DEBUG)
{
nasal_dbg debugger;
debugger.run(gen,linker);
}
else if(cmd&VM_EXECTIME)
{
clock_t t=clock();
vm.run(gen,linker,cmd&VM_OPCALLNUM,cmd&VM_DBGINFO);
std::cout<<"process exited after "<<((double)(clock()-t))/CLOCKS_PER_SEC<<"s.\n";
}
else if(cmd&VM_EXEC)
vm.run(gen,linker,cmd&VM_OPCALLNUM,cmd&VM_DBGINFO);
}
int main(int argc,const char* argv[])
{
if(argc<=1)
{
logo();
return 0;
}
if(argc==2)
{
std::string s(argv[1]);
if(s=="-v" || s=="--version")
logo();
else if(s=="-h" || s=="--help")
help();
else if(s[0]!='-')
execute(s,VM_EXEC);
else
err();
return 0;
}
std::unordered_map<std::string,uint32_t> cmdlst={
{"--lex",VM_LEXINFO},{"-l",VM_LEXINFO},
{"--ast",VM_ASTINFO},{"-a",VM_ASTINFO},
{"--code",VM_CODEINFO},{"-c",VM_CODEINFO},
{"--exec",VM_EXEC},{"-e",VM_EXEC},
{"--opcnt",VM_OPCALLNUM|VM_EXEC},{"-o",VM_OPCALLNUM|VM_EXEC},
{"--time",VM_EXECTIME|VM_EXEC},{"-t",VM_EXECTIME|VM_EXEC},
{"--detail",VM_DBGINFO|VM_EXEC},{"-d",VM_DBGINFO|VM_EXEC},
{"--optimize",VM_OPTIMIZE},{"-op",VM_OPTIMIZE},
{"--debug",VM_DEBUG},{"-dbg",VM_DEBUG}
};
uint32_t cmd=0;
for(int i=1;i<argc-1;++i)
{
if(cmdlst.count(argv[i]))
cmd|=cmdlst[argv[i]];
else
err();
}
execute(argv[argc-1],cmd);
return 0;
}

47
makefile Normal file
View File

@@ -0,0 +1,47 @@
.PHONY=test
nasal:main.cpp nasal_ast.h nasal_err.h nasal_builtin.h nasal_opt.h nasal_codegen.h\
nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal_dbg.h nasal.h
clang++ -std=c++11 -O3 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
nasal.exe:main.cpp nasal_ast.h nasal_err.h nasal_builtin.h nasal_opt.h nasal_codegen.h\
nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal_dbg.h nasal.h
g++ -std=c++11 -O3 main.cpp -o nasal.exe -fno-exceptions -Wshadow -Wall -static
test:nasal
@ ./nasal -op -e test/ascii-art.nas
@ ./nasal -op -a -c test/bf.nas
@ ./nasal -op -a -c test/bfcolored.nas
@ ./nasal -op -a -c test/bfconvertor.nas
@ ./nasal -op -e -d test/bfs.nas
@ ./nasal -op -t test/bigloop.nas
@ ./nasal -op -e test/bp.nas
@ ./nasal -op -e -d test/calc.nas
@ ./nasal -op -e test/choice.nas
@ ./nasal -op -e test/class.nas
@ ./nasal -op -e test/diff.nas
-@ ./nasal -op -d test/exception.nas
@ ./nasal -op -t -d test/fib.nas
@ ./nasal -op -e test/filesystem.nas
@ ./nasal -op -e -d test/hexdump.nas
@ ./nasal -op -e test/json.nas
@ ./nasal -op -e test/leetcode1319.nas
@ ./nasal -op -e -d test/lexer.nas
@ ./nasal -op -e -d test/life.nas
@ ./nasal -op -t test/loop.nas
@ ./nasal -op -t -d test/mandel.nas
@ ./nasal -op -t -d test/mandelbrot.nas
@ ./nasal -op -t -d -o test/md5.nas
-@ ./nasal -op -t -d -o test/md5compare.nas
-@ ./nasal -op -d test/module_test.nas
@ ./nasal -op -e test/nasal_test.nas
@ ./nasal -op -t -d test/pi.nas
@ ./nasal -op -t -d test/prime.nas
@ ./nasal -op -t -d test/props_sim.nas
@ ./nasal -op -e test/qrcode.nas
@ ./nasal -op -t -d test/quick_sort.nas
@ ./nasal -op -e test/scalar.nas
-@ ./nasal -op -c -t test/snake.nas
@ ./nasal -op -c -e test/trait.nas
-@ ./nasal -op -c -t test/tetris.nas
@ ./nasal -op -c -t -d test/turingmachine.nas
@ ./nasal -op -c -t -d -o test/ycombinator.nas
@ ./nasal -op -e test/wavecollapse.nas

34
module/fib.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include <iostream>
#include "../nasal.h"
double fibonaci(double x){
if(x<=2)
return x;
return fibonaci(x-1)+fibonaci(x-2);
}
extern "C" nasal_ref fib(std::vector<nasal_ref>& args,nasal_gc& gc){
std::cout<<"[mod] this is the first test module of nasal\n";
if(!args.size())
return builtin_err("fib","lack arguments");
nasal_ref num=args[0];
if(num.type!=vm_num)
return builtin_err("extern_fib","\"num\" must be number");
return {vm_num,fibonaci(num.to_number())};
}
extern "C" nasal_ref quick_fib(std::vector<nasal_ref>& args,nasal_gc& gc){
std::cout<<"[mod] this is the first test module of nasal\n";
if(!args.size())
return builtin_err("fib","lack arguments");
nasal_ref num=args[0];
if(num.type!=vm_num)
return builtin_err("extern_quick_fib","\"num\" must be number");
if(num.num()<2)
return num;
double a=1,b=1,res=0;
for(double i=1;i<num.num();i+=1){
res=a+b;
a=b;
b=res;
}
return {vm_num,res};
}

74
module/keyboard.cpp Normal file
View File

@@ -0,0 +1,74 @@
#include "../nasal.h"
#include <iostream>
#ifdef _WIN32
#include <conio.h>
#else
#include <fcntl.h>
#include <termios.h>
#endif
#ifndef _WIN32
static struct termios init_termios;
static struct termios new_termios;
static int peek_char=-1;
int kbhit(){
unsigned char ch=0;
int nread=0;
if(peek_char!=-1)
return 1;
int flag=fcntl(0,F_GETFL);
fcntl(0,F_SETFL,flag|O_NONBLOCK);
nread=read(0,&ch,1);
fcntl(0,F_SETFL,flag);
if(nread==1){
peek_char=ch;
return 1;
}
return 0;
}
int getch(){
int ch=0;
if(peek_char!=-1){
ch=peek_char;
peek_char=-1;
return ch;
}
read(0,&ch,1);
return ch;
}
#endif
extern "C" nasal_ref nas_getch(std::vector<nasal_ref>& args,nasal_gc& gc){
return {vm_num,(double)getch()};
}
extern "C" nasal_ref nas_kbhit(std::vector<nasal_ref>& args,nasal_gc& gc){
return {vm_num,(double)kbhit()};
}
extern "C" nasal_ref nas_noblock(std::vector<nasal_ref>& args,nasal_gc& gc){
if(kbhit())
return {vm_num,(double)getch()};
return nil;
}
extern "C" nasal_ref nas_init(std::vector<nasal_ref>& args,nasal_gc& gc){
#ifndef _WIN32
tcflush(0,TCIOFLUSH);
tcgetattr(0,&init_termios);
new_termios=init_termios;
new_termios.c_lflag&=~(ICANON|ECHO|ECHONL|ECHOE);
// vmin=0 is nonblock input, but in wsl there is a bug that will block input
// so we use fcntl to write the nonblock input
new_termios.c_cc[VMIN]=1;
new_termios.c_cc[VTIME]=0;
tcsetattr(0,TCSANOW,&new_termios);
#endif
return nil;
}
extern "C" nasal_ref nas_close(std::vector<nasal_ref>& args,nasal_gc& gc){
#ifndef _WIN32
tcflush(0,TCIOFLUSH);
tcsetattr(0,TCSANOW,&init_termios);
#endif
return nil;
}

13
module/libfib.nas Normal file
View File

@@ -0,0 +1,13 @@
import("lib.nas");
var libfib=func(){
var dl=dylib.dlopen("./module/libfib."~(os.platform()=="windows"?"dll":"so"));
var fib=dylib.dlsym(dl,"fib");
var qfib=dylib.dlsym(dl,"quick_fib");
var call=dylib.dlcall;
return
{
fib: func(x){return call(fib,x)},
qfib:func(x){return call(qfib,x)}
};
}();

47
module/libkey.nas Normal file
View File

@@ -0,0 +1,47 @@
import("lib.nas");
var libkey=func(){
var lib=dylib.dlopen("./module/libkey"~(os.platform()=="windows"?".dll":".so"));
var kb=dylib.dlsym(lib,"nas_kbhit");
var gt=dylib.dlsym(lib,"nas_getch");
var nb=dylib.dlsym(lib,"nas_noblock");
var init=dylib.dlsym(lib,"nas_init");
var cls=dylib.dlsym(lib,"nas_close");
var call=dylib.dlcall;
var is_init=0;
return {
init:func(){
# change io mode to no echo
call(init);
is_init=1;
},
kbhit:func(){
# check if kerboard is hit
# if keyboard is hit this function will return 1
# until getch() gets all the input characters
# and the input flow becomes empty
if(!is_init)
me.init();
return call(kb);
},
getch:func(){
# get input one character without echo
# block until get one input
if(!is_init)
me.init();
return call(gt);
},
nonblock:func(){
# nonblock input without echo
if(!is_init)
me.init();
return call(nb);
},
close:func(){
# must call this function before exiting the program
# this will change terminal mode to normal io mode
call(cls);
dylib.dlclose(lib);
}
}
}();

23
module/makefile Normal file
View File

@@ -0,0 +1,23 @@
.PHONY=clean all mingw-all
libfib.so: fib.cpp
clang++ -c -O3 fib.cpp -fPIC -o fib.o
clang++ -shared -o libfib.so fib.o
rm fib.o
libfib.dll: fib.cpp
g++ -c -O3 fib.cpp -fPIC -o fib.o
g++ -shared -o libfib.dll fib.o
libkey.so: keyboard.cpp
clang++ -c -O3 keyboard.cpp -fPIC -o keyboard.o
clang++ -shared -o libkey.so keyboard.o
rm keyboard.o
libkey.dll: keyboard.cpp
g++ -c -O3 keyboard.cpp -fPIC -o keyboard.o -static
g++ -shared -o libkey.dll keyboard.o -static
clean:
rm *.o *.so *.dll *.dylib
all: libfib.so libkey.so
@ echo "build done"
mingw-all: libfib.dll libkey.dll
@ echo "build done"

View File

@@ -20,7 +20,7 @@ hashmember::=
id|string ':' calculation
;
function::=
func argument_list expressions
func {argument_list} exprs|expr
;
argument_list::=
'(' [{id ','} ([id '...']|{id '=' scalar ','})] ')'
@@ -35,7 +35,7 @@ expr::=
|continue_expr
|break_expr
;
expressions::=
exprs::=
'{' {expr} '}'
;
calculation::=
@@ -63,7 +63,6 @@ unary::=
;
scalar::=
function {call_scalar}
|[func] identifier {call_scalar}
|vector {call_scalar}
|hash {call_scalar}
|number
@@ -109,18 +108,18 @@ loop::=
|forei_loop
;
while_loop::=
while '(' calculation ')' expressions
while '(' calculation ')' exprs
;
for_loop::=
for '(' [definition|calculation] ';' [calculation] ';' [calculation] ')' expressions
for '(' [definition|calculation] ';' [calculation] ';' [calculation] ')' exprs
;
forei_loop::=
(forindex | foreach) '(' (definition | calculation) ';' calculation ')' expressions
(forindex | foreach) '(' (definition | calculation) ';' calculation ')' exprs
;
conditional::=
if '(' calculation ')' expressions
{elsif '(' calculation ')' expressions}
[else expressions]
if '(' calculation ')' exprs
{elsif '(' calculation ')' exprs}
[else exprs]
;
continue_expr::=
continue

235
nasal.h
View File

@@ -1,12 +1,14 @@
#ifndef __NASAL_H__
#define __NASAL_H__
#pragma GCC optimize(2)
#define __nasver "9.0"
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <cstdint>
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>
@@ -15,114 +17,179 @@
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <thread>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#include <unordered_map>
/*
check if a string can be converted to a number
if this string cannot be converted to a number,it will return nan
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#include <sys/wait.h>
#endif
#ifdef __linux__
#define PRTHEX64 "%lx"
#define PRTHEX64_8 "%.8lx"
#define PRTINT64 "%ld"
#else
#define PRTHEX64 "%llx"
#define PRTHEX64_8 "%.8llx"
#define PRTINT64 "%lld"
#endif
inline double hex_to_double(const char* str)
{
double ret=0;
for(;*str;++str)
{
ret*=16;
if('0'<=*str && *str<='9')
ret+=(*str-'0');
else if('a'<=*str && *str<='f')
ret+=(*str-'a'+10);
else if('A'<=*str && *str<='F')
ret+=(*str-'A'+10);
else
return nan("");
}
return ret;
double ret=0;
for(;*str;++str)
{
ret*=16;
if('0'<=*str && *str<='9')
ret+=(*str-'0');
else if('a'<=*str && *str<='f')
ret+=(*str-'a'+10);
else if('A'<=*str && *str<='F')
ret+=(*str-'A'+10);
else
return nan("");
}
return ret;
}
inline double oct_to_double(const char* str)
{
double ret=0;
for(;*str;++str)
{
ret*=8;
if('0'<=*str && *str<='8')
ret+=(*str-'0');
else
return nan("");
}
return ret;
double ret=0;
for(;*str;++str)
{
ret*=8;
if('0'<=*str && *str<'8')
ret+=(*str-'0');
else
return nan("");
}
return ret;
}
inline double dec_to_double(const char* str)
{
double ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9')
ret=ret*10+(*str++-'0');
if(!*str) return ret;
if(*str=='.')
{
if(!*++str) return nan("");
num_pow=0.1;
while('0'<=*str && *str<='9')
{
ret+=num_pow*(*str++-'0');
num_pow*=0.1;
}
if(!*str) return ret;
}
if(*str!='e' && *str!='E')
return nan("");
if(!*++str) return nan("");
if(*str=='-' || *str=='+')
negative=(*str++=='-'? -1:1);
if(!*str) return nan("");
num_pow=0;
for(;*str;++str)
{
if('0'<=*str && *str<='9')
num_pow=num_pow*10+(*str-'0');
else
return nan("");
}
return ret*std::pow(10,negative*num_pow);
double ret=0,negative=1,num_pow=0;
while('0'<=*str && *str<='9')
ret=ret*10+(*str++-'0');
if(!*str) return ret;
if(*str=='.')
{
if(!*++str) return nan("");
num_pow=0.1;
while('0'<=*str && *str<='9')
{
ret+=num_pow*(*str++-'0');
num_pow*=0.1;
}
if(!*str) return ret;
}
if(*str!='e' && *str!='E')
return nan("");
if(!*++str) return nan("");
if(*str=='-' || *str=='+')
negative=(*str++=='-'? -1:1);
if(!*str) return nan("");
num_pow=0;
for(;*str;++str)
{
if('0'<=*str && *str<='9')
num_pow=num_pow*10+(*str-'0');
else
return nan("");
}
return ret*std::pow(10,negative*num_pow);
}
double str2num(const char* str)
{
bool is_negative=false;
double ret_num=0;
if(*str=='-' || *str=='+')
is_negative=(*str++=='-');
if(!*str)
return nan("");
if(str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str+2);
else if(str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str+2);
else
ret_num=dec_to_double(str);
return is_negative?-ret_num:ret_num;
bool is_negative=false;
double ret_num=0;
if(*str=='-' || *str=='+')
is_negative=(*str++=='-');
if(!*str)
return nan("");
if(str[0]=='0' && str[1]=='x')
ret_num=hex_to_double(str+2);
else if(str[0]=='0' && str[1]=='o')
ret_num=oct_to_double(str+2);
else
ret_num=dec_to_double(str);
return is_negative?-ret_num:ret_num;
}
/*
trans_number_to_string:
convert number to string
*/
std::string num2str(double number)
int utf8_hdchk(char head)
{
std::ostringstream ss;
ss<<number;
return ss.str();
// RFC-2279 but in fact now we use RFC-3629 so nbytes is less than 4
uint8_t c=(uint8_t)head;
uint32_t nbytes=0;
if((c>>5)==0x06) // 110x xxxx (10xx xxxx)^1
nbytes=1;
if((c>>4)==0x0e) // 1110 xxxx (10xx xxxx)^2
nbytes=2;
if((c>>3)==0x1e) // 1111 0xxx (10xx xxxx)^3
nbytes=3;
// these should not be true
if((c>>2)==0x3e) // 1111 10xx (10xx xxxx)^4
nbytes=4;
if((c>>1)==0x7e) // 1111 110x (10xx xxxx)^5
nbytes=5;
if(c==0xfe) // 1111 1110 (10xx xxxx)^6
nbytes=6;
return nbytes;
}
std::string rawstr(const std::string& str)
{
std::string ret("");
for(auto i:str)
{
#ifdef _WIN32
// windows ps or cmd doesn't output unicode normally
// if 'chcp65001' is not enabled, so we output the hex
if(i<=0)
{
ret+="\\x";
ret+="0123456789abcdef"[(i>>4)&15];
ret+="0123456789abcdef"[i&15];
continue;
}
#endif
switch(i)
{
case '\0': ret+="\\0"; break;
case '\a': ret+="\\a"; break;
case '\b': ret+="\\b"; break;
case '\e': ret+="\\e"; break;
case '\t': ret+="\\t"; break;
case '\n': ret+="\\n"; break;
case '\v': ret+="\\v"; break;
case '\f': ret+="\\f"; break;
case '\r': ret+="\\r"; break;
case '\\': ret+="\\\\";break;
case '\'': ret+="\\\'";break;
case '\"': ret+="\\\"";break;
default: ret+=i; break;
}
}
return ret;
}
#include "nasal_err.h"
#include "nasal_lexer.h"
#include "nasal_ast.h"
#include "nasal_parse.h"
#include "nasal_import.h"
#include "nasal_opt.h"
#include "nasal_gc.h"
#include "nasal_builtin.h"
#include "nasal_codegen.h"
#include "nasal_vm.h"
#include "nasal_dbg.h"
#endif

View File

@@ -3,140 +3,245 @@
enum ast_node
{
ast_null=0,
ast_root,ast_block,
ast_nil,ast_num,ast_str,ast_id,ast_func,ast_hash,ast_vec,
ast_hashmember,ast_call,ast_callh,ast_callv,ast_callf,ast_subvec,
ast_args,ast_default_arg,ast_dynamic_id,
ast_and,ast_or,
ast_equal,ast_addeq,ast_subeq,ast_multeq,ast_diveq,ast_lnkeq,
ast_cmpeq,ast_neq,
ast_less,ast_leq,
ast_grt,ast_geq,
ast_add,ast_sub,ast_mult,ast_div,ast_link,
ast_neg,ast_not,
ast_trino,
ast_for,ast_forindex,ast_foreach,ast_while,ast_new_iter,
ast_conditional,ast_if,ast_elsif,ast_else,
ast_multi_id,ast_multi_scalar,
ast_def,ast_multi_assign,
ast_continue,ast_break,ast_ret
ast_null=0, // null node
ast_root, // mark the root node of ast
ast_block, // expression block
ast_file, // used to store which file the sub-tree is on, only used in main block
ast_nil, // nil keyword
ast_num, // number, basic value type
ast_str, // string, basic value type
ast_id, // identifier
ast_func, // func keyword
ast_hash, // hash, basic value type
ast_vec, // vector, basic value type
ast_pair, // pair of key and value in hashmap
ast_call, // mark a sub-tree of calling an identifier
ast_callh, // id.name
ast_callv, // id[index]
ast_callf, // id()
ast_subvec, // id[index:index]
ast_args, // mark a sub-tree of function parameters
ast_default, // default parameter
ast_dynamic, // dynamic parameter
ast_and, // and keyword
ast_or, // or keyword
ast_equal, // =
ast_addeq, // +=
ast_subeq, // -=
ast_multeq, // *=
ast_diveq, // /=
ast_lnkeq, // ~=
ast_cmpeq, // ==
ast_neq, // !=
ast_less, // <
ast_leq, // <=
ast_grt, // >
ast_geq, // >=
ast_add, // +
ast_sub, // -
ast_mult, // *
ast_div, // /
ast_link, // ~
ast_neg, // -
ast_not, // ~
ast_trino, // ?:
ast_for, // for keyword
ast_forindex, // forindex keyword
ast_foreach, // foreach keyword
ast_while, // while
ast_iter, // iterator, used in forindex/foreach
ast_conditional, // mark a sub-tree of conditional expression
ast_if, // if keyword
ast_elsif, // elsif keyword
ast_else, // else keyword
ast_multi_id, // multi identifiers sub-tree
ast_multi_scalar,// multi value sub-tree
ast_def, // definition
ast_multi_assign,// multi assignment sub-tree
ast_continue, // continue keyword, only used in loop
ast_break, // break keyword, only used in loop
ast_ret // return keyword, only used in function block
};
const char* ast_name[]=
{
"null",
"root","block",
"nil","num","str","id","func","hash","vec",
"hashmember","call","callh","callv","callf","subvec",
"args","deflt_arg","dyn_id",
"and","or",
"=","+=","-=","*=","/=","~=",
"==","!=",
"<","<=",
">",">=",
"+","-","*","/","~",
"unary-","unary!",
"root",
"block",
"file",
"nil",
"num",
"str",
"id",
"func",
"hash",
"vec",
"hashmember",
"call",
"callh",
"callv",
"callf",
"subvec",
"args",
"default",
"dynamic",
"and",
"or",
"=",
"+=",
"-=",
"*=",
"/=",
"~=",
"==",
"!=",
"<",
"<=",
">",
">=",
"+",
"-",
"*",
"/",
"~",
"unary-",
"unary!",
"trino",
"for","forindex","foreach","while","iter",
"conditional","if","elsif","else",
"multi_id","multi_scalar",
"def","multi_assign",
"continue","break","return"
"for",
"forindex",
"foreach",
"while",
"iter",
"conditional",
"if",
"elsif",
"else",
"multi-id",
"multi-scalar",
"def",
"multi-assign",
"continue",
"break",
"return",
nullptr
};
class nasal_ast
{
private:
int line;
int type;
double num;
std::string str;
std::vector<nasal_ast> children;
uint32_t _line;
uint32_t _type;
double _num;
std::string _str;
std::vector<nasal_ast> _child;
public:
nasal_ast(){line=0;type=ast_null;}
nasal_ast(int l,int t){line=l;type=t;}
nasal_ast(const uint32_t l=0,const uint32_t t=ast_null):_line(l),_type(t),_num(0){}
nasal_ast(const nasal_ast&);
nasal_ast(nasal_ast&&);
void print(int,bool);
void clear();
nasal_ast& operator=(const nasal_ast&);
nasal_ast& operator=(nasal_ast&&);
void print_ast(int);
void clear();
void add_child(nasal_ast&& ast){children.push_back(std::move(ast));}
void set_line(int l){line=l;}
void set_type(int t){type=t;}
void set_str(std::string& s){str=s;}
void set_num(double n){num=n;}
int get_line(){return line;}
int get_type(){return type;}
double get_num(){return num;}
std::string& get_str(){return str;}
std::vector<nasal_ast>& get_children(){return children;}
nasal_ast& operator[](const int index){return _child[index];}
const nasal_ast& operator[](const int index) const {return _child[index];}
size_t size() const {return _child.size();}
void add(nasal_ast&& ast){_child.push_back(std::move(ast));}
void add(const nasal_ast& ast){_child.push_back(ast);}
void set_line(const uint32_t l){_line=l;}
void set_type(const uint32_t t){_type=t;}
void set_str(const std::string& s){_str=s;}
void set_num(const double n){_num=n;}
inline uint32_t line() const {return _line;}
inline uint32_t type() const {return _type;}
inline double num() const {return _num;}
inline const std::string& str() const {return _str;}
inline const std::vector<nasal_ast>& child() const {return _child;}
inline std::vector<nasal_ast>& child(){return _child;}
};
nasal_ast::nasal_ast(const nasal_ast& tmp)
nasal_ast::nasal_ast(const nasal_ast& tmp):
_str(tmp._str),_child(tmp._child)
{
line=tmp.line;
type=tmp.type;
str =tmp.str;
num =tmp.num;
children=tmp.children;
return;
_line=tmp._line;
_type=tmp._type;
_num =tmp._num;
}
nasal_ast::nasal_ast(nasal_ast&& tmp)
{
line=tmp.line;
type=tmp.type;
str.swap(tmp.str);
num =tmp.num;
children.swap(tmp.children);
return;
_line=tmp._line;
_type=tmp._type;
_num =tmp._num;
_str.swap(tmp._str);
_child.swap(tmp._child);
}
nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
{
line=tmp.line;
type=tmp.type;
str=tmp.str;
num=tmp.num;
children=tmp.children;
_line=tmp._line;
_type=tmp._type;
_num=tmp._num;
_str=tmp._str;
_child=tmp._child;
return *this;
}
nasal_ast& nasal_ast::operator=(nasal_ast&& tmp)
{
line=tmp.line;
type=tmp.type;
str.swap(tmp.str);
num=tmp.num;
children.swap(tmp.children);
_line=tmp._line;
_type=tmp._type;
_num=tmp._num;
_str.swap(tmp._str);
_child.swap(tmp._child);
return *this;
}
void nasal_ast::clear()
{
line=0;
str="";
num=0;
type=ast_null;
children.clear();
return;
_line=0;
_num=0;
_str="";
_type=ast_null;
_child.clear();
}
void nasal_ast::print_ast(int depth)
void nasal_ast::print(int depth,bool last=false)
{
for(int i=0;i<depth;++i)
std::cout<<"| ";
std::cout<<ast_name[type];
if(type==ast_str || type==ast_id || type==ast_default_arg || type==ast_dynamic_id || type==ast_callh)
std::cout<<":"<<str;
else if(type==ast_num)
std::cout<<":"<<num;
static std::vector<std::string> intentation={};
for(auto& i:intentation)
std::cout<<i;
std::cout<<ast_name[_type];
if(
_type==ast_str ||
_type==ast_id ||
_type==ast_default ||
_type==ast_dynamic ||
_type==ast_callh)
std::cout<<":"<<rawstr(_str);
else if(_type==ast_num || _type==ast_file)
std::cout<<":"<<_num;
std::cout<<'\n';
for(auto& i:children)
i.print_ast(depth+1);
return;
if(last && depth)
intentation.back()=" ";
else if(!last && depth)
#ifdef _WIN32
intentation.back()="| ";
#else
intentation.back()="";
#endif
for(uint32_t i=0;i<_child.size();++i)
{
#ifdef _WIN32
intentation.push_back(i==_child.size()-1?"`-":"|-");
#else
intentation.push_back(i==_child.size()-1?"└─":"├─");
#endif
_child[i].print(depth+1,i==_child.size()-1);
intentation.pop_back();
}
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

295
nasal_dbg.h Normal file
View File

@@ -0,0 +1,295 @@
#ifndef __NASAL_DBG_H__
#define __NASAL_DBG_H__
#include "nasal_vm.h"
class nasal_dbg:public nasal_vm
{
private:
bool next_step;
uint16_t bk_fidx;
uint32_t bk_line;
file_line src;
std::vector<std::string> parse(const std::string&);
uint16_t get_fileindex(const std::string&);
void err();
void help();
void stepinfo();
void interact();
public:
nasal_dbg():
next_step(false),
bk_fidx(0),bk_line(0){}
void run(
const nasal_codegen&,
const nasal_import&
);
};
std::vector<std::string> nasal_dbg::parse(const std::string& cmd)
{
std::vector<std::string> res;
std::string tmp="";
for(uint32_t i=0;i<cmd.length();++i)
{
if(cmd[i]==' ' && tmp.length())
{
res.push_back(tmp);
tmp="";
continue;
}
tmp+=cmd[i];
}
if(tmp.length())
res.push_back(tmp);
return res;
}
uint16_t nasal_dbg::get_fileindex(const std::string& filename)
{
for(uint16_t i=0;i<files_size;++i)
if(filename==files[i])
return i;
return 65535;
}
void nasal_dbg::err()
{
std::cerr
<<"incorrect command\n"
<<"input \'h\' to get help\n";
}
void nasal_dbg::help()
{
std::cout
<<"<option>\n"
<<"\th, help | get help\n"
<<"\tbt, backtrace | get function call trace\n"
<<"\tc, continue | run program until break point or exit\n"
<<"\tf, file | see all the compiled files\n"
<<"\tg, global | see global values\n"
<<"\tl, local | see local values\n"
<<"\tu, upval | see upvalue\n"
<<"\ta, all | show global,local and upvalue\n"
<<"\tn, next | execute next bytecode\n"
<<"\tq, exit | exit debugger\n"
<<"<option> <filename> <line>\n"
<<"\tbk, break | set break point\n";
}
void nasal_dbg::stepinfo()
{
uint32_t begin,end;
uint32_t line=bytecode[pc].line==0?0:bytecode[pc].line-1;
src.load(files[bytecode[pc].fidx]);
printf("\nsource code:\n");
begin=(line>>3)==0?0:((line>>3)<<3);
end=(1+(line>>3))<<3;
for(uint32_t i=begin;i<end && i<src.size();++i)
printf("%s\t%s\n",i==line?"-->":" ",src[i].c_str());
printf("next bytecode:\n");
begin=(pc>>3)==0?0:((pc>>3)<<3);
end=(1+(pc>>3))<<3;
for(uint32_t i=begin;i<end && bytecode[i].op!=op_exit;++i)
bytecodeinfo(i==pc?"-->\t":" \t",i);
stackinfo(5);
}
void nasal_dbg::interact()
{
// special operand
if(bytecode[pc].op==op_intg)
{
std::cout
<<"[debug] nasal debug mode\n"
<<"input \'h\' to get help\n";
}
else if(bytecode[pc].op==op_exit)
return;
if(
(bytecode[pc].fidx!=bk_fidx || bytecode[pc].line!=bk_line) && // break point
!next_step // next step
)return;
next_step=false;
std::string cmd;
stepinfo();
while(1)
{
printf(">> ");
std::getline(std::cin,cmd);
auto res=parse(cmd);
if(res.size()==1)
{
if(res[0]=="h" || res[0]=="help")
help();
else if(res[0]=="bt" || res[0]=="backtrace")
traceback();
else if(res[0]=="c" || res[0]=="continue")
return;
else if(res[0]=="f" || res[0]=="file")
for(size_t i=0;i<files_size;++i)
printf("[%zu] %s\n",i,files[i].c_str());
else if(res[0]=="g" || res[0]=="global")
global_state();
else if(res[0]=="l" || res[0]=="local")
local_state();
else if(res[0]=="u" || res[0]=="upval")
upval_state();
else if(res[0]=="a" || res[0]=="all")
detail();
else if(res[0]=="n" || res[0]=="next")
{
next_step=true;
return;
}
else if(res[0]=="q" || res[0]=="exit")
std::exit(0);
else
err();
}
else if(res.size()==3 && (res[0]=="bk" || res[0]=="break"))
{
bk_fidx=get_fileindex(res[1]);
if(bk_fidx==65535)
{
printf("cannot find file named \"%s\"\n",res[1].c_str());
bk_fidx=0;
}
int tmp=atoi(res[2].c_str());
if(tmp<=0)
printf("incorrect line number \"%s\"\n",res[2].c_str());
else
bk_line=tmp;
}
else
err();
}
}
void nasal_dbg::run(
const nasal_codegen& gen,
const nasal_import& linker)
{
detail_info=true;
init(gen.get_strs(),gen.get_nums(),gen.get_code(),linker.get_file());
const void* opr_table[]=
{
&&vmexit, &&intg, &&intl, &&loadg,
&&loadl, &&loadu, &&pnum, &&pnil,
&&pstr, &&newv, &&newh, &&newf,
&&happ, &&para, &&defpara,&&dynpara,
&&unot, &&usub, &&add, &&sub,
&&mul, &&div, &&lnk, &&addc,
&&subc, &&mulc, &&divc, &&lnkc,
&&addeq, &&subeq, &&muleq, &&diveq,
&&lnkeq, &&addeqc, &&subeqc, &&muleqc,
&&diveqc, &&lnkeqc, &&meq, &&eq,
&&neq, &&less, &&leq, &&grt,
&&geq, &&lessc, &&leqc, &&grtc,
&&geqc, &&pop, &&jmp, &&jt,
&&jf, &&counter, &&findex, &&feach,
&&callg, &&calll, &&upval, &&callv,
&&callvi, &&callh, &&callfv, &&callfh,
&&callb, &&slcbegin, &&slcend, &&slc,
&&slc2, &&mcallg, &&mcalll, &&mupval,
&&mcallv, &&mcallh, &&ret
};
std::vector<const void*> code;
for(auto& i:gen.get_code())
{
code.push_back(opr_table[i.op]);
imm.push_back(i.num);
}
// goto the first operand
goto *code[pc];
vmexit:
if(gc.top>=canary)
die("stack overflow");
gc.clear();
imm.clear();
printf("[debug] debugger exited\n");
return;
#define dbg(op) {interact();op();if(gc.top<canary)goto *code[++pc];goto vmexit;}
intg: dbg(opr_intg );
intl: dbg(opr_intl );
loadg: dbg(opr_loadg );
loadl: dbg(opr_loadl );
loadu: dbg(opr_loadu );
pnum: dbg(opr_pnum );
pnil: dbg(opr_pnil );
pstr: dbg(opr_pstr );
newv: dbg(opr_newv );
newh: dbg(opr_newh );
newf: dbg(opr_newf );
happ: dbg(opr_happ );
para: dbg(opr_para );
defpara: dbg(opr_defpara );
dynpara: dbg(opr_dynpara );
unot: dbg(opr_unot );
usub: dbg(opr_usub );
add: dbg(opr_add );
sub: dbg(opr_sub );
mul: dbg(opr_mul );
div: dbg(opr_div );
lnk: dbg(opr_lnk );
addc: dbg(opr_addc );
subc: dbg(opr_subc );
mulc: dbg(opr_mulc );
divc: dbg(opr_divc );
lnkc: dbg(opr_lnkc );
addeq: dbg(opr_addeq );
subeq: dbg(opr_subeq );
muleq: dbg(opr_muleq );
diveq: dbg(opr_diveq );
lnkeq: dbg(opr_lnkeq );
addeqc: dbg(opr_addeqc );
subeqc: dbg(opr_subeqc );
muleqc: dbg(opr_muleqc );
diveqc: dbg(opr_diveqc );
lnkeqc: dbg(opr_lnkeqc );
meq: dbg(opr_meq );
eq: dbg(opr_eq );
neq: dbg(opr_neq );
less: dbg(opr_less );
leq: dbg(opr_leq );
grt: dbg(opr_grt );
geq: dbg(opr_geq );
lessc: dbg(opr_lessc );
leqc: dbg(opr_leqc );
grtc: dbg(opr_grtc );
geqc: dbg(opr_geqc );
pop: dbg(opr_pop );
jmp: dbg(opr_jmp );
jt: dbg(opr_jt );
jf: dbg(opr_jf );
counter: dbg(opr_counter );
findex: dbg(opr_findex );
feach: dbg(opr_feach );
callg: dbg(opr_callg );
calll: dbg(opr_calll );
upval: dbg(opr_upval );
callv: dbg(opr_callv );
callvi: dbg(opr_callvi );
callh: dbg(opr_callh );
callfv: dbg(opr_callfv );
callfh: dbg(opr_callfh );
callb: dbg(opr_callb );
slcbegin:dbg(opr_slcbegin);
slcend: dbg(opr_slcend );
slc: dbg(opr_slc );
slc2: dbg(opr_slc2 );
mcallg: dbg(opr_mcallg );
mcalll: dbg(opr_mcalll );
mupval: dbg(opr_mupval );
mcallv: dbg(opr_mcallv );
mcallh: dbg(opr_mcallh );
ret: dbg(opr_ret );
}
#endif

78
nasal_err.h Normal file
View File

@@ -0,0 +1,78 @@
#ifndef __NASAL_ERR_H__
#define __NASAL_ERR_H__
#include <iostream>
#include <fstream>
#include <cstring>
class file_line
{
protected:
std::string file;
std::vector<std::string> res;
public:
void load(const std::string& f)
{
if(file==f) // don't need to load a loaded file
return;
file=f;
res.clear();
std::ifstream fin(f,std::ios::binary);
if(fin.fail())
{
std::cerr<<"[src] cannot open file <"<<f<<">\n";
std::exit(1);
}
std::string line;
while(!fin.eof())
{
std::getline(fin,line);
res.push_back(line);
}
}
void clear()
{
std::vector<std::string> tmp;
res.swap(tmp);
}
const std::string& operator[](const uint32_t line){return res[line];}
const std::string& name(){return file;}
size_t size(){return res.size();}
};
class nasal_err:public file_line
{
private:
uint32_t error;
public:
nasal_err():error(0){}
void err(const char* stage,const std::string& info,const char end='\n')
{
++error;
std::cerr<<"["<<stage<<"] "<<info<<end;
}
void err(const char* stage,uint32_t line,uint32_t column,const std::string& info)
{
++error;
if(!line)
{
std::cerr<<"["<<stage<<"] "<<file<<": "<<info<<'\n';
return;
}
std::cerr<<"["<<stage<<"] "<<file<<":"<<line<<":"<<column<<" "<<info<<"\n"<<res[line-1]<<'\n';
for(int i=0;i<(int)column-1;++i)
std::cerr<<char(" \t"[res[line-1][i]=='\t']);
std::cerr<<"^\n";
}
void err(const char* stage,uint32_t line,const std::string& info)
{
++error;
if(!line)
std::cerr<<"["<<stage<<"] "<<file<<": "<<info<<'\n';
else
std::cerr<<"["<<stage<<"] "<<file<<":"<<line<<" "<<info<<"\n"<<res[line-1]<<'\n';
}
void chkerr(){if(error)std::exit(1);}
};
#endif

View File

@@ -3,207 +3,331 @@
enum nasal_type
{
vm_nil=0,
/* none-gc object */
vm_none=0,
vm_cnt,
vm_addr,
vm_ret,
vm_nil,
vm_num,
/* gc object */
vm_str,
vm_func,
vm_vec,
vm_hash,
vm_upval,
vm_obj,
vm_type_size
};
// change parameters here to make your own efficient gc
// better set bigger number on vm_num and vm_vec
const int increment[vm_type_size]=
// better set bigger number on vm_vec
const uint32_t initialize[vm_type_size]=
{
0, // vm_nil,in fact it is not in use
65536,// vm_num
256, // vm_str
16, // vm_func
2048, // vm_vec
8 // vm_hash
/* none-gc object */
0, // vm_none, error type
0, // vm_count, used in foreach/forindex
0, // vm_addr, used to store local address pointers
0, // vm_ret, used to store call-return address
0, // vm_nil
0, // vm_num
/* gc object */
128, // vm_str
512, // vm_func
128, // vm_vec
64, // vm_hash
512, // vm_upval
16 // vm_obj
};
const uint32_t increment[vm_type_size]=
{
/* none-gc object */
0, // vm_none, error type
0, // vm_count, used in foreach/forindex
0, // vm_addr, used to store local address pointers
0, // vm_ret, used to store call-return address
0, // vm_nil
0, // vm_num
/* gc object */
1024,// vm_str
512, // vm_func
8192,// vm_vec
1024,// vm_hash
128, // vm_upval
256 // vm_obj
};
struct nasal_val;//declaration of nasal_val
struct nasal_vec; // vector
struct nasal_hash; // hashmap(dict)
struct nasal_func; // function(lambda)
struct nasal_upval;// upvalue
struct nasal_obj; // special objects
struct nasal_val; // nasal_val includes gc-managed types
struct nasal_vec// 24 bytes
struct nasal_ref
{
std::vector<nasal_val*> elems;
uint8_t type;
union
{
uint32_t ret;
int64_t cnt;
double num;
nasal_ref* addr;
nasal_val* gcobj;
} value;
// vm_none/vm_nil
nasal_ref(const uint8_t t=vm_none):type(t){}
// vm_ret
nasal_ref(const uint8_t t,const uint32_t n):type(t){value.ret=n;}
// vm_cnt
nasal_ref(const uint8_t t,const int64_t n):type(t){value.cnt=n;}
// vm_num
nasal_ref(const uint8_t t,const double n):type(t){value.num=n;}
// vm_str/vm_func/vm_vec/vm_hash/vm_upval/vm_obj
nasal_ref(const uint8_t t,nasal_val* n):type(t){value.gcobj=n;}
// vm_addr
nasal_ref(const uint8_t t,nasal_ref* n):type(t){value.addr=n;}
nasal_ref(const nasal_ref& nr):type(nr.type),value(nr.value){}
nasal_ref& operator=(const nasal_ref& nr)
{
type=nr.type;
value=nr.value;
return *this;
}
bool operator==(const nasal_ref& nr){return type==nr.type && value.gcobj==nr.value.gcobj;}
bool operator!=(const nasal_ref& nr){return type!=nr.type || value.gcobj!=nr.value.gcobj;}
// number and string can be translated to each other
double to_number();
std::string to_string();
void print();
nasal_val* get_val(int);
nasal_val** get_mem(int);
bool objchk(uint32_t);
inline nasal_ref* addr();
inline uint32_t ret ();
inline int64_t& cnt ();
inline double num ();
inline std::string& str ();
inline nasal_vec& vec ();
inline nasal_hash& hash();
inline nasal_func& func();
inline nasal_upval& upval();
inline nasal_obj& obj ();
};
struct nasal_hash// 56 bytes
struct nasal_vec
{
std::unordered_map<std::string,nasal_val*> elems;
bool printed;
std::vector<nasal_ref> elems;
void print();
nasal_val* get_val(std::string&);
nasal_val** get_mem(std::string&);
nasal_vec():printed(false){}
void print();
size_t size(){return elems.size();}
nasal_ref get_val(const int);
nasal_ref* get_mem(const int);
};
struct nasal_func// 120 bytes
struct nasal_hash
{
int32_t dynpara;// dynamic parameter name index in hash
uint32_t offset; // arguments will be loaded into local scope from this offset
uint32_t entry; // pc will set to entry-1 to call this function
std::vector<nasal_val*> default_para;// default value(nasal_val*)
std::unordered_map<std::string,int> key_table;// parameter name hash
std::vector<nasal_val*> closure;// closure will be loaded to gc.local.back() as the local scope
bool printed;
std::unordered_map<std::string,nasal_ref> elems;
nasal_func();
nasal_hash():printed(false){}
void print();
size_t size(){return elems.size();}
nasal_ref get_val(const std::string&);
nasal_ref* get_mem(const std::string&);
};
struct nasal_func
{
int32_t dynpara; // dynamic parameter name index in hash.
uint32_t entry; // pc will set to entry-1 to call this function
uint32_t psize; // used to load default parameters to a new function
uint32_t lsize; // used to expand memory space for local values on stack
std::vector<nasal_ref> local; // local scope with default value(nasal_ref)
std::vector<nasal_ref> upvalue; // closure
std::unordered_map<std::string,size_t> keys; // parameter name table, size_t begins from 1
nasal_func():dynpara(-1),entry(0),psize(0),lsize(0){}
void clear();
};
struct nasal_val// 16 bytes
struct nasal_upval
{
bool onstk;
uint32_t size;
nasal_ref* stk;
std::vector<nasal_ref> elems;
nasal_upval(){onstk=true;stk=nullptr;size=0;}
nasal_ref& operator[](const int i){return onstk?stk[i]:elems[i];}
void clear(){onstk=true;elems.clear();size=0;}
};
struct nasal_obj
{
enum obj_type
{
null,
file=1,
dir,
dylib,
externfunc
};
/* RAII constructor */
/* new object is initialized when creating */
uint32_t type;
void* ptr;
/* RAII destroyer */
/* default destroyer does nothing */
typedef void (*dest)(void*);
dest destructor;
nasal_obj():type(obj_type::null),ptr(nullptr),destructor(nullptr){}
~nasal_obj(){clear();}
void clear()
{
if(destructor && ptr)
destructor(ptr);
ptr=nullptr;
destructor=nullptr;
}
};
const uint8_t GC_UNCOLLECTED=0;
const uint8_t GC_COLLECTED =1;
const uint8_t GC_FOUND =2;
struct nasal_val
{
#define GC_UNCOLLECTED 0
#define GC_COLLECTED 1
#define GC_FOUND 2
uint8_t mark;
uint16_t type;
uint8_t type;
uint8_t unmut; // used to mark if a string is unmutable
union
{
double num;
std::string* str;
nasal_vec* vec;
nasal_hash* hash;
nasal_func* func;
nasal_upval* upval;
nasal_obj* obj;
}ptr;
nasal_val(int);
nasal_val(uint8_t);
~nasal_val();
double to_number();
std::string to_string();
};
/*functions of nasal_vec*/
nasal_val* nasal_vec::get_val(int index)
nasal_ref nasal_vec::get_val(const int index)
{
int vec_size=elems.size();
if(index<-vec_size || index>=vec_size)
return nullptr;
return elems[index>=0?index:index+vec_size];
int size=elems.size();
if(index<-size || index>=size)
return {vm_none};
return elems[index>=0?index:index+size];
}
nasal_val** nasal_vec::get_mem(int index)
nasal_ref* nasal_vec::get_mem(const int index)
{
int vec_size=elems.size();
if(index<-vec_size || index>=vec_size)
int size=elems.size();
if(index<-size || index>=size)
return nullptr;
return &elems[index>=0?index:index+vec_size];
return &elems[index>=0?index:index+size];
}
void nasal_vec::print()
{
std::cout<<'[';
for(auto i:elems)
if(!elems.size() || printed)
{
switch(i->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<i->ptr.num; break;
case vm_str: std::cout<<*i->ptr.str; break;
case vm_vec: i->ptr.vec->print(); break;
case vm_hash: i->ptr.hash->print(); break;
case vm_func: std::cout<<"func(...){...}"; break;
}
std::cout<<',';
std::cout<<(elems.size()?"[..]":"[]");
return;
}
std::cout<<']';
return;
printed=true;
size_t iter=0;
std::cout<<'[';
for(auto& i:elems)
{
i.print();
std::cout<<",]"[(++iter)==elems.size()];
}
printed=false;
}
/*functions of nasal_hash*/
nasal_val* nasal_hash::get_val(std::string& key)
nasal_ref nasal_hash::get_val(const std::string& key)
{
nasal_val* ret_addr=nullptr;
if(elems.count(key))
return elems[key];
else if(elems.count("parents"))
{
nasal_val* val_addr=elems["parents"];
if(val_addr->type==vm_vec)
for(auto i:val_addr->ptr.vec->elems)
nasal_ref ret(vm_none);
nasal_ref val=elems["parents"];
if(val.type==vm_vec)
for(auto& i:val.vec().elems)
{
if(i->type==vm_hash)
ret_addr=i->ptr.hash->get_val(key);
if(ret_addr)
return ret_addr;
if(i.type==vm_hash)
ret=i.hash().get_val(key);
if(ret.type!=vm_none)
return ret;
}
}
return nullptr;
return {vm_none};
}
nasal_val** nasal_hash::get_mem(std::string& key)
nasal_ref* nasal_hash::get_mem(const std::string& key)
{
nasal_val** mem_addr=nullptr;
if(elems.count(key))
return &elems[key];
else if(elems.count("parents"))
{
nasal_val* val_addr=elems["parents"];
if(val_addr->type==vm_vec)
for(auto i:val_addr->ptr.vec->elems)
nasal_ref* addr=nullptr;
nasal_ref val=elems["parents"];
if(val.type==vm_vec)
for(auto& i:val.vec().elems)
{
if(i->type==vm_hash)
mem_addr=i->ptr.hash->get_mem(key);
if(mem_addr)
return mem_addr;
if(i.type==vm_hash)
addr=i.hash().get_mem(key);
if(addr)
return addr;
}
}
return nullptr;
}
void nasal_hash::print()
{
if(!elems.size() || printed)
{
std::cout<<(elems.size()?"{..}":"{}");
return;
}
printed=true;
size_t iter=0;
std::cout<<'{';
for(auto& i:elems)
{
std::cout<<i.first<<':';
nasal_val* tmp=i.second;
switch(tmp->type)
{
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<tmp->ptr.num; break;
case vm_str: std::cout<<*tmp->ptr.str; break;
case vm_vec: tmp->ptr.vec->print(); break;
case vm_hash: tmp->ptr.hash->print(); break;
case vm_func: std::cout<<"func(...){...}"; break;
}
std::cout<<',';
i.second.print();
std::cout<<",}"[(++iter)==elems.size()];
}
std::cout<<'}';
return;
printed=false;
}
/*functions of nasal_func*/
nasal_func::nasal_func()
{
dynpara=-1;
return;
}
void nasal_func::clear()
{
dynpara=-1;
default_para.clear();
key_table.clear();
closure.clear();
return;
local.clear();
upvalue.clear();
keys.clear();
}
/*functions of nasal_val*/
nasal_val::nasal_val(int val_type)
nasal_val::nasal_val(uint8_t val_type)
{
mark=GC_COLLECTED;
type=val_type;
switch(type)
unmut=0;
switch(val_type)
{
case vm_num: ptr.num=0; break;
case vm_str: ptr.str=new std::string; break;
case vm_vec: ptr.vec=new nasal_vec; break;
case vm_hash: ptr.hash=new nasal_hash; break;
case vm_func: ptr.func=new nasal_func; break;
case vm_str: ptr.str=new std::string; break;
case vm_vec: ptr.vec=new nasal_vec; break;
case vm_hash: ptr.hash=new nasal_hash; break;
case vm_func: ptr.func=new nasal_func; break;
case vm_upval:ptr.upval=new nasal_upval;break;
case vm_obj: ptr.obj=new nasal_obj; break;
}
return;
}
nasal_val::~nasal_val()
{
@@ -213,83 +337,123 @@ nasal_val::~nasal_val()
case vm_vec: delete ptr.vec; break;
case vm_hash: delete ptr.hash; break;
case vm_func: delete ptr.func; break;
case vm_upval:delete ptr.upval;break;
case vm_obj: delete ptr.obj; break;
}
type=vm_nil;
return;
}
double nasal_val::to_number()
double nasal_ref::to_number()
{
return type!=vm_str?value.num:str2num(str().c_str());
}
std::string nasal_ref::to_string()
{
if(type==vm_str)
return str2num(ptr.str->c_str());
return ptr.num;
}
std::string nasal_val::to_string()
{
if(type==vm_str)
return *ptr.str;
return str();
else if(type==vm_num)
return num2str(ptr.num);
{
std::string tmp=std::to_string(num());
tmp.erase(tmp.find_last_not_of('0')+1,std::string::npos);
tmp.erase(tmp.find_last_not_of('.')+1,std::string::npos);
return tmp;
}
return "";
}
void nasal_ref::print()
{
switch(type)
{
case vm_none: std::cout<<"undefined"; break;
case vm_nil: std::cout<<"nil"; break;
case vm_num: std::cout<<value.num; break;
case vm_str: std::cout<<str(); break;
case vm_vec: vec().print(); break;
case vm_hash: hash().print(); break;
case vm_func: std::cout<<"func(..){..}";break;
case vm_obj: std::cout<<"<object>"; break;
}
}
bool nasal_ref::objchk(uint32_t objtype)
{
return type==vm_obj && obj().type==objtype && obj().ptr;
}
inline nasal_ref* nasal_ref::addr (){return value.addr; }
inline uint32_t nasal_ref::ret (){return value.ret; }
inline int64_t& nasal_ref::cnt (){return value.cnt; }
inline double nasal_ref::num (){return value.num; }
inline std::string& nasal_ref::str (){return *value.gcobj->ptr.str; }
inline nasal_vec& nasal_ref::vec (){return *value.gcobj->ptr.vec; }
inline nasal_hash& nasal_ref::hash (){return *value.gcobj->ptr.hash; }
inline nasal_func& nasal_ref::func (){return *value.gcobj->ptr.func; }
inline nasal_upval& nasal_ref::upval(){return *value.gcobj->ptr.upval;}
inline nasal_obj& nasal_ref::obj (){return *value.gcobj->ptr.obj; }
const nasal_ref zero={vm_num,(double)0};
const nasal_ref one ={vm_num,(double)1};
const nasal_ref nil ={vm_nil,(double)0};
struct nasal_gc
{
#define STACK_MAX_DEPTH (65536)
nasal_val* zero_addr; // reserved address of nasal_val,type vm_num, 0
nasal_val* one_addr; // reserved address of nasal_val,type vm_num, 1
nasal_val* nil_addr; // reserved address of nasal_val,type vm_nil
nasal_val* val_stack[STACK_MAX_DEPTH+16];// 16 reserved to avoid stack overflow
nasal_val** stack_top; // stack top
std::vector<nasal_val*> num_addrs; // reserved address for const vm_num
std::vector<nasal_val*> str_addrs; // reserved address for const vm_str
std::vector<nasal_val*> slice_stack; // slice stack for vec[val,val,val:val]
static const uint32_t stack_depth=8192; // depth of value stack
nasal_ref funcr; // function register
nasal_ref stack[stack_depth]; // the last one is reserved to avoid stack overflow
nasal_ref* top; // stack top
std::vector<nasal_ref> strs; // reserved address for const vm_str
std::vector<nasal_val*> memory; // gc memory
std::queue <nasal_val*> free_list[vm_type_size]; // gc free list
std::vector<nasal_val*> global;
std::list<std::vector<nasal_val*>> local;
std::queue<nasal_val*> free_list[vm_type_size]; // gc free list
/* upvalue is a temporary space to store upvalues */
/* if no new functions generated in local scope */
/* upvalue will pushback(nil) */
/* if new functions generated in local scope */
/* they will share the same upvalue stored here */
std::vector<nasal_ref> upvalue;
uint64_t size[vm_type_size];
uint64_t count[vm_type_size];
void mark();
void sweep();
void gc_init(std::vector<double>&,std::vector<std::string>&);
void gc_clear();
nasal_val* gc_alloc(int);
nasal_val* builtin_alloc(int);
void init(const std::vector<std::string>&);
void clear();
void info();
nasal_ref alloc(const uint8_t);
nasal_ref builtin_alloc(const uint8_t);
};
/* gc functions */
void nasal_gc::mark()
{
std::queue<nasal_val*> bfs;
for(auto i:global)
std::queue<nasal_ref> bfs;
bfs.push(funcr);
for(auto& i:upvalue)
bfs.push(i);
for(auto& i:local)
for(auto j:i)
bfs.push(j);
for(auto i:slice_stack)
bfs.push(i);
for(nasal_val** i=val_stack;i<=stack_top;++i)
for(nasal_ref* i=stack;i<=top;++i)
bfs.push(*i);
while(!bfs.empty())
{
nasal_val* tmp=bfs.front();
nasal_ref tmp=bfs.front();
bfs.pop();
if(tmp->mark) continue;
tmp->mark=GC_FOUND;
if(tmp->type==vm_vec)
for(auto i:tmp->ptr.vec->elems)
bfs.push(i);
else if(tmp->type==vm_hash)
for(auto& i:tmp->ptr.hash->elems)
bfs.push(i.second);
else if(tmp->type==vm_func)
if(tmp.type<=vm_num || tmp.value.gcobj->mark) continue;
tmp.value.gcobj->mark=GC_FOUND;
switch(tmp.type)
{
for(auto i:tmp->ptr.func->closure)
bfs.push(i);
for(auto i:tmp->ptr.func->default_para)
if(i)
case vm_vec:
for(auto& i:tmp.vec().elems)
bfs.push(i);
break;
case vm_hash:
for(auto& i:tmp.hash().elems)
bfs.push(i.second);
break;
case vm_func:
for(auto& i:tmp.func().local)
bfs.push(i);
for(auto& i:tmp.func().upvalue)
bfs.push(i);
break;
case vm_upval:
for(auto& i:tmp.upval().elems)
bfs.push(i);
}
}
return;
}
void nasal_gc::sweep()
{
@@ -299,10 +463,12 @@ void nasal_gc::sweep()
{
switch(i->type)
{
case vm_str: i->ptr.str->clear(); break;
case vm_vec: i->ptr.vec->elems.clear(); break;
case vm_hash:i->ptr.hash->elems.clear();break;
case vm_func:i->ptr.func->clear(); break;
case vm_str: i->ptr.str->clear(); break;
case vm_vec: i->ptr.vec->elems.clear(); break;
case vm_hash: i->ptr.hash->elems.clear();break;
case vm_func: i->ptr.func->clear(); break;
case vm_upval:i->ptr.upval->clear(); break;
case vm_obj: i->ptr.obj->clear(); break;
}
free_list[i->type].push(i);
i->mark=GC_COLLECTED;
@@ -310,102 +476,100 @@ void nasal_gc::sweep()
else if(i->mark==GC_FOUND)
i->mark=GC_UNCOLLECTED;
}
return;
}
void nasal_gc::gc_init(std::vector<double>& nums,std::vector<std::string>& strs)
void nasal_gc::init(const std::vector<std::string>& s)
{
for(int i=vm_num;i<vm_type_size;++i)
for(int j=0;j<increment[i];++j)
// initiaize function register
funcr=nil;
for(uint8_t i=0;i<vm_type_size;++i)
size[i]=count[i]=0;
for(uint8_t i=vm_str;i<vm_type_size;++i)
for(uint32_t j=0;j<initialize[i];++j)
{
nasal_val* tmp=new nasal_val(i);
memory.push_back(tmp);
free_list[i].push(tmp);
}
stack_top=val_stack; // set stack_top to val_stack
zero_addr=new nasal_val(vm_num); // init constant 0
zero_addr->ptr.num=0;
one_addr=new nasal_val(vm_num); // init constant 1
one_addr->ptr.num=1;
nil_addr=new nasal_val(vm_nil); // init nil
*val_stack=nil_addr; // the first space will not store any values,but gc checks
// init constant numbers
num_addrs.resize(nums.size());
for(int i=0;i<nums.size();++i)
{
num_addrs[i]=new nasal_val(vm_num);
num_addrs[i]->ptr.num=nums[i];
}
top=stack;
// init constant strings
str_addrs.resize(strs.size());
for(int i=0;i<strs.size();++i)
strs.resize(s.size());
for(uint32_t i=0;i<strs.size();++i)
{
str_addrs[i]=new nasal_val(vm_str);
*str_addrs[i]->ptr.str=strs[i];
strs[i]={vm_str,new nasal_val(vm_str)};
strs[i].value.gcobj->unmut=1;
strs[i].str()=s[i];
}
return;
}
void nasal_gc::gc_clear()
void nasal_gc::clear()
{
for(auto i:memory)
delete i;
memory.clear();
for(int i=0;i<vm_type_size;++i)
upvalue.clear();
for(uint8_t i=0;i<vm_type_size;++i)
while(!free_list[i].empty())
free_list[i].pop();
global.clear();
local.clear();
slice_stack.clear();
delete nil_addr;
delete one_addr;
delete zero_addr;
for(auto i:num_addrs)
delete i;
num_addrs.clear();
for(auto i:str_addrs)
delete i;
str_addrs.clear();
return;
for(auto& i:strs)
delete i.value.gcobj;
strs.clear();
}
nasal_val* nasal_gc::gc_alloc(int type)
void nasal_gc::info()
{
const char* name[]={
"null ","cnt ","addr ",
"ret ","nil ","num ",
"str ","func ","vec ",
"hash ","upval","obj "
};
std::cout<<"\ngarbage collector info:\n";
for(uint8_t i=vm_str;i<vm_type_size;++i)
std::cout<<" "<<name[i]<<" | "<<count[i]<<"\n";
std::cout<<"\nmemory allocator info(max size):\n";
for(uint8_t i=vm_str;i<vm_type_size;++i)
std::cout<<" "<<name[i]<<" | "<<initialize[i]+size[i]*increment[i]<<"(+"<<size[i]<<")\n";
}
nasal_ref nasal_gc::alloc(uint8_t type)
{
if(free_list[type].empty())
{
++count[type];
mark();
sweep();
}
if(free_list[type].empty())
for(int i=0;i<increment[type];++i)
{
++size[type];
for(uint32_t i=0;i<increment[type];++i)
{
nasal_val* tmp=new nasal_val(type);
memory.push_back(tmp);
free_list[type].push(tmp);
}
nasal_val* ret=free_list[type].front();
ret->mark=GC_UNCOLLECTED;
}
nasal_ref ret={type,free_list[type].front()};
ret.value.gcobj->mark=GC_UNCOLLECTED;
free_list[type].pop();
return ret;
}
nasal_val* nasal_gc::builtin_alloc(int type)
nasal_ref nasal_gc::builtin_alloc(uint8_t type)
{
// when running a builtin function,alloc will run more than one time
// this may cause mark-sweep in gc_alloc
// this may cause mark-sweep in gc::alloc
// and the value got before will be collected,this is a fatal error
// so use builtin_alloc in builtin functions if this function uses alloc more then one time
if(free_list[type].empty())
for(int i=0;i<increment[type];++i)
{
++size[type];
for(uint32_t i=0;i<increment[type];++i)
{
nasal_val* tmp=new nasal_val(type);
memory.push_back(tmp);
free_list[type].push(tmp);
}
nasal_val* ret=free_list[type].front();
ret->mark=GC_UNCOLLECTED;
}
nasal_ref ret={type,free_list[type].front()};
ret.value.gcobj->mark=GC_UNCOLLECTED;
free_list[type].pop();
return ret;
}

View File

@@ -1,129 +1,151 @@
#ifndef __NASAL_IMPORT_H__
#define __NASAL_IMPORT_H__
class nasal_import
{
private:
int error;
nasal_lexer import_lex;
nasal_parse import_par;
nasal_ast import_ast;
std::vector<std::string> filename_table;
void die(std::string&,const char*);
bool check_import(nasal_ast&);
bool check_exist(std::string&);
void linker(nasal_ast&,nasal_ast&&);
nasal_ast file_import(nasal_ast&);
nasal_ast load(nasal_ast&);
public:
int get_error(){return error;}
void link(nasal_ast&);
nasal_ast& get_root(){return import_ast;}
};
void nasal_import::die(std::string& filename,const char* error_stage)
{
++error;
std::cout<<">> [import] in <\""<<filename<<"\">: error(s) occurred in "<<error_stage<<".\n";
return;
}
bool nasal_import::check_import(nasal_ast& node)
{
/*
only this kind of node can be recognized as 'import':
call
id:import
call_func
string:'filename'
*/
if(node.get_type()!=ast_call)
return false;
std::vector<nasal_ast>& ref_vec=node.get_children();
if(ref_vec.size()!=2)
return false;
if(ref_vec[0].get_str()!="import")
return false;
if(ref_vec[1].get_type()!=ast_callf)
return false;
if(ref_vec[1].get_children().size()!=1 || ref_vec[1].get_children()[0].get_type()!=ast_str)
return false;
return true;
}
bool nasal_import::check_exist(std::string& file)
{
// avoid importing the same file
for(auto& fname:filename_table)
if(file==fname)
return true;
filename_table.push_back(file);
return false;
}
void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
{
// add children of add_root to the back of root
for(auto& i:add_root.get_children())
root.add_child(std::move(i));
return;
}
nasal_ast nasal_import::file_import(nasal_ast& node)
{
// initializing
nasal_ast tmp(0,ast_root);
// get filename and set node to ast_null
std::string filename=node.get_children()[1].get_children()[0].get_str();
node.clear();
// avoid infinite loading loop
if(check_exist(filename))
return tmp;
// start importing...
import_lex.openfile(filename);
import_lex.scanner();
if(import_lex.get_error())
{
die(filename,"lexer");
return tmp;
}
import_par.set_toklist(import_lex.get_token_list());
import_lex.get_token_list().clear();
import_par.main_process();
if(import_par.get_error())
{
die(filename,"parser");
return tmp;
}
tmp=std::move(import_par.get_root());
import_par.get_root().clear();
// check if tmp has 'import'
return load(tmp);
}
nasal_ast nasal_import::load(nasal_ast& root)
{
nasal_ast new_root(0,ast_root);
for(auto& i:root.get_children())
if(check_import(i))
linker(new_root,file_import(i));
// add root to the back of new_root
linker(new_root,std::move(root));
return new_root;
}
void nasal_import::link(nasal_ast& root)
{
// initializing
error=0;
filename_table.clear();
import_ast.clear();
// scan root and import files,then generate a new ast and return to import_ast
import_ast=load(root);
return;
}
#ifndef __NASAL_IMPORT_H__
#define __NASAL_IMPORT_H__
class nasal_import
{
private:
bool lib_loaded;
nasal_err& nerr;
std::vector<std::string> files;
bool check_import(const nasal_ast&);
bool check_exist(const std::string&);
void linker(nasal_ast&,nasal_ast&&);
nasal_ast file_import(nasal_ast&);
nasal_ast lib_import();
nasal_ast load(nasal_ast&,uint16_t);
public:
nasal_import(nasal_err& e):lib_loaded(false),nerr(e){}
void link(nasal_parse&,const std::string&);
const std::vector<std::string>& get_file() const {return files;}
};
bool nasal_import::check_import(const nasal_ast& node)
{
/*
only this kind of node can be recognized as 'import':
call
|_id:import
|_call_func
|_string:'filename'
*/
return (
node.type()==ast_call &&
node.size()==2 &&
node[0].str()=="import" &&
node[1].type()==ast_callf &&
node[1].size()==1 &&
node[1][0].type()==ast_str
);
}
bool nasal_import::check_exist(const std::string& file)
{
// avoid importing the same file
for(auto& fname:files)
if(file==fname)
return true;
files.push_back(file);
return false;
}
void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
{
// add children of add_root to the back of root
for(auto& i:add_root.child())
root.add(std::move(i));
}
nasal_ast nasal_import::file_import(nasal_ast& node)
{
nasal_lexer lex(nerr);
nasal_parse par(nerr);
// get filename and set node to ast_null
std::string filename=node[1][0].str();
node.clear();
// avoid infinite loading loop
if(check_exist(filename))
return {0,ast_root};
if(access(filename.c_str(),F_OK)==-1)
{
nerr.err("link","cannot open file <"+filename+">");
return {0,ast_root};
}
// start importing...
lex.scan(filename);
par.compile(lex);
nasal_ast tmp=std::move(par.ast());
// check if tmp has 'import'
return load(tmp,files.size()-1);
}
nasal_ast nasal_import::lib_import()
{
nasal_lexer lex(nerr);
nasal_parse par(nerr);
const std::vector<std::string> libpath=
{
"lib.nas",
"stl/lib.nas"
};
std::string filename="";
for(auto& i:libpath)
if(access(i.c_str(),F_OK)!=-1)
{
filename=i;
break;
}
if(!filename.length())
{
std::string paths="";
for(auto& i:libpath)
paths+=" "+i+"\n";
nerr.err("link","cannot find lib file in these paths:\n"+paths,' ');
nerr.chkerr();
return {0,ast_root};
}
// avoid infinite loading loop
if(check_exist(filename))
return {0,ast_root};
// start importing...
lex.scan(filename);
par.compile(lex);
nasal_ast tmp=std::move(par.ast());
// check if tmp has 'import'
return load(tmp,files.size()-1);
}
nasal_ast nasal_import::load(nasal_ast& root,uint16_t fileindex)
{
nasal_ast new_root(0,ast_root);
if(!lib_loaded)
{
linker(new_root,lib_import());
lib_loaded=true;
}
for(auto& i:root.child())
if(check_import(i))
linker(new_root,file_import(i));
// add root to the back of new_root
nasal_ast file_head(0,ast_file);
file_head.set_num(fileindex);
new_root.add(std::move(file_head));
linker(new_root,std::move(root));
return new_root;
}
void nasal_import::link(nasal_parse& parse,const std::string& self)
{
// initializing
files={self};
// scan root and import files,then generate a new ast and return to import_ast
// the main file's index is 0
parse.ast()=load(parse.ast(),0);
}
#endif

View File

@@ -1,371 +1,393 @@
#ifndef __NASAL_LEXER_H__
#define __NASAL_LEXER_H__
#define IS_IDENTIFIER(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z'))
#define IS_HEX_NUMBER(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'))
#define IS_OCT_NUMEBR(c) ('0'<=c&&c<='7')
#define IS_DIGIT(c) ('0'<=c&&c<='9')
#define IS_STRING(c) (c=='\''||c=='\"'||c=='`')
// single operators have only one character
#define IS_SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
// calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
#define IS_CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
#define IS_NOTE(c) (c=='#')
enum token_type
{
tok_null=0,
tok_num,tok_str,tok_id,
tok_for,tok_forindex,tok_foreach,tok_while,
tok_var,tok_func,tok_break,tok_continue,
tok_ret,tok_if,tok_elsif,tok_else,tok_nil,
tok_lcurve,tok_rcurve,
tok_lbracket,tok_rbracket,
tok_lbrace,tok_rbrace,
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
tok_eq,
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
tok_eof
};
struct
{
const char* str;
int tok_type;
}token_table[]=
{
{"for" ,tok_for },
{"forindex",tok_forindex },
{"foreach" ,tok_foreach },
{"while" ,tok_while },
{"var" ,tok_var },
{"func" ,tok_func },
{"break" ,tok_break },
{"continue",tok_continue },
{"return" ,tok_ret },
{"if" ,tok_if },
{"elsif" ,tok_elsif },
{"else" ,tok_else },
{"nil" ,tok_nil },
{"(" ,tok_lcurve },
{")" ,tok_rcurve },
{"[" ,tok_lbracket },
{"]" ,tok_rbracket },
{"{" ,tok_lbrace },
{"}" ,tok_rbrace },
{";" ,tok_semi },
{"and" ,tok_and },
{"or" ,tok_or },
{"," ,tok_comma },
{"." ,tok_dot },
{"..." ,tok_ellipsis },
{"?" ,tok_quesmark },
{":" ,tok_colon },
{"+" ,tok_add },
{"-" ,tok_sub },
{"*" ,tok_mult },
{"/" ,tok_div },
{"~" ,tok_link },
{"!" ,tok_not },
{"=" ,tok_eq },
{"+=" ,tok_addeq },
{"-=" ,tok_subeq },
{"*=" ,tok_multeq },
{"/=" ,tok_diveq },
{"~=" ,tok_lnkeq },
{"==" ,tok_cmpeq },
{"!=" ,tok_neq },
{"<" ,tok_less },
{"<=" ,tok_leq },
{">" ,tok_grt },
{">=" ,tok_geq },
{nullptr ,-1 }
};
struct token
{
int line;
int type;
std::string str;
token(int l=0,int t=tok_null,std::string s=""){line=l;type=t;str=s;return;}
};
class nasal_lexer
{
private:
int error;
int res_size;
int line;
int ptr;
std::string line_code;
std::vector<char> res;
std::vector<token> token_list;
int get_tok_type(std::string&);
void die(const char*);
std::string id_gen();
std::string num_gen();
std::string str_gen();
public:
void openfile(std::string&);
void scanner();
void print_token();
int get_error(){return error;}
std::vector<token>& get_token_list(){return token_list;}
};
void nasal_lexer::openfile(std::string& filename)
{
error=0;
res.clear();
std::ifstream fin(filename,std::ios::binary);
if(fin.fail())
{
++error;
std::cout<<">> [lexer] cannot open file \""<<filename<<"\".\n";
fin.close();
return;
}
while(!fin.eof())
{
char c=fin.get();
if(fin.eof())
break;
res.push_back(c);
}
fin.close();
return;
}
int nasal_lexer::get_tok_type(std::string& tk_str)
{
for(int i=0;token_table[i].str;++i)
if(tk_str==token_table[i].str)
return token_table[i].tok_type;
return tok_null;
}
void nasal_lexer::die(const char* error_info)
{
++error;
std::cout<<">> [lexer] line "<<line<<" column "<<line_code.length()<<": \n"<<line_code<<"\n";
for(auto i:line_code)
std::cout<<(i=='\t'?'\t':' ');
std::cout<<"^"<<error_info<<'\n';
return;
}
std::string nasal_lexer::id_gen()
{
std::string token_str="";
while(ptr<res_size && (IS_IDENTIFIER(res[ptr])||IS_DIGIT(res[ptr])))
token_str+=res[ptr++];
line_code+=token_str;
return token_str;
// after running this process, ptr will point to the next token's beginning character
}
std::string nasal_lexer::num_gen()
{
// generate hex number
if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='x')
{
std::string token_str="0x";
ptr+=2;
while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
token_str+=res[ptr++];
line_code+=token_str;
if(token_str=="0x")
die("incorrect number.");
return token_str;
}
// generate oct number
else if(ptr+1<res_size && res[ptr]=='0' && res[ptr+1]=='o')
{
std::string token_str="0o";
ptr+=2;
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
token_str+=res[ptr++];
line_code+=token_str;
if(token_str=="0o")
die("incorrect number.");
return token_str;
}
// generate dec number
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
std::string token_str="";
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
if(ptr<res_size && res[ptr]=='.')
{
token_str+=res[ptr++];
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
// "xxxx." is not a correct number
if(token_str.back()=='.')
{
line_code+=token_str;
die("incorrect number.");
return "0";
}
}
if(ptr<res_size && (res[ptr]=='e' || res[ptr]=='E'))
{
token_str+=res[ptr++];
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
token_str+=res[ptr++];
while(ptr<res_size && IS_DIGIT(res[ptr]))
token_str+=res[ptr++];
// "xxxe(-|+)" is not a correct number
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
{
line_code+=token_str;
die("incorrect number.");
return "0";
}
}
line_code+=token_str;
return token_str;
}
std::string nasal_lexer::str_gen()
{
std::string token_str="";
char str_begin=res[ptr];
line_code+=str_begin;
while(++ptr<res_size && res[ptr]!=str_begin)
{
line_code+=res[ptr];
if(res[ptr]=='\n')
{
line_code="";
++line;
}
if(res[ptr]=='\\' && ptr+1<res_size)
{
line_code+=res[++ptr];
switch(res[ptr])
{
case 'a': token_str.push_back('\a');break;
case 'b': token_str.push_back('\b');break;
case 'f': token_str.push_back('\f');break;
case 'n': token_str.push_back('\n');break;
case 'r': token_str.push_back('\r');break;
case 't': token_str.push_back('\t');break;
case 'v': token_str.push_back('\v');break;
case '?': token_str.push_back('\?');break;
case '0': token_str.push_back('\0');break;
case '\\':token_str.push_back('\\');break;
case '\'':token_str.push_back('\'');break;
case '\"':token_str.push_back('\"');break;
default: token_str.push_back(res[ptr]);break;
}
continue;
}
token_str+=res[ptr];
}
// check if this string ends with a " or '
if(ptr++>=res_size)
die("get EOF when generating string.");
if(str_begin=='`' && token_str.length()!=1)
die("\'`\' is used for string that includes one character.");
return token_str;
}
void nasal_lexer::scanner()
{
token_list.clear();
line=1;
ptr=0;
line_code="";
res_size=res.size();
std::string token_str;
while(ptr<res_size)
{
while(ptr<res_size && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
{
// these characters will be ignored, and '\n' will cause ++line
line_code+=res[ptr];
if(res[ptr++]=='\n')
{
++line;
line_code="";
}
}
if(ptr>=res_size) break;
if(IS_IDENTIFIER(res[ptr]))
{
token_str=id_gen();
token new_token(line,get_tok_type(token_str),token_str);
if(!new_token.type)
new_token.type=tok_id;
token_list.push_back(new_token);
}
else if(IS_DIGIT(res[ptr]))
{
token_str=num_gen();
token_list.push_back({line,tok_num,token_str});
}
else if(IS_STRING(res[ptr]))
{
token_str=str_gen();
token_list.push_back({line,tok_str,token_str});
}
else if(IS_SINGLE_OPERATOR(res[ptr]))
{
token_str=res[ptr];
line_code+=res[ptr];
int type=get_tok_type(token_str);
if(!type)
die("incorrect operator.");
token_list.push_back({line,type,token_str});
++ptr;
}
else if(res[ptr]=='.')
{
if(ptr+2<res_size && res[ptr+1]=='.' && res[ptr+2]=='.')
{
token_str="...";
ptr+=3;
}
else
{
token_str=".";
++ptr;
}
line_code+=token_str;
token_list.push_back({line,get_tok_type(token_str),token_str});
}
else if(IS_CALC_OPERATOR(res[ptr]))
{
// get calculation operator
token_str=res[ptr++];
if(ptr<res_size && res[ptr]=='=')
token_str+=res[ptr++];
line_code+=token_str;
token_list.push_back({line,get_tok_type(token_str),token_str});
}
else if(IS_NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
while(++ptr<res_size && res[ptr]!='\n');
else
{
line_code+=res[ptr++];
die("unknown character.");
}
}
token_list.push_back({line,tok_eof,""});
res.clear();
return;
}
void nasal_lexer::print_token()
{
for(auto tok:token_list)
std::cout<<"("<<tok.line<<" | "<<tok.str<<")\n";
return;
}
#ifndef __NASAL_LEXER_H__
#define __NASAL_LEXER_H__
#define ID(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||(c<0))
#define HEX(c) (('0'<=c&&c<='9')||('a'<=c&&c<='f')||('A'<=c && c<='F'))
#define OCT(c) ('0'<=c&&c<='7')
#define DIGIT(c) ('0'<=c&&c<='9')
#define STR(c) (c=='\''||c=='\"'||c=='`')
// single operators have only one character
#define SINGLE_OPERATOR(c) (c=='('||c==')'||c=='['||c==']'||c=='{'||c=='}'||c==','||c==';'||c=='|'||c==':'||\
c=='?'||c=='`'||c=='&'||c=='@'||c=='%'||c=='$'||c=='^'||c=='\\')
// calculation operators may have two chars, for example: += -= *= /= ~= != == >= <=
#define CALC_OPERATOR(c) (c=='='||c=='+'||c=='-'||c=='*'||c=='!'||c=='/'||c=='<'||c=='>'||c=='~')
#define NOTE(c) (c=='#')
enum token_type
{
tok_null=0,// null token default token type
tok_num, // number basic token type
tok_str, // string basic token type
tok_id, // identifier basic token type
tok_for,tok_forindex,tok_foreach,tok_while,
tok_var,tok_func,tok_break,tok_continue,
tok_ret,tok_if,tok_elsif,tok_else,tok_nil,
tok_lcurve,tok_rcurve,
tok_lbracket,tok_rbracket,
tok_lbrace,tok_rbrace,
tok_semi,tok_and,tok_or,tok_comma,tok_dot,tok_ellipsis,tok_quesmark,
tok_colon,tok_add,tok_sub,tok_mult,tok_div,tok_link,tok_not,
tok_eq,
tok_addeq,tok_subeq,tok_multeq,tok_diveq,tok_lnkeq,
tok_cmpeq,tok_neq,tok_less,tok_leq,tok_grt,tok_geq,
tok_eof // end of token list
};
struct
{
const char* str;
const uint32_t tok_type;
}token_table[]=
{
{"for" ,tok_for },
{"forindex",tok_forindex },
{"foreach" ,tok_foreach },
{"while" ,tok_while },
{"var" ,tok_var },
{"func" ,tok_func },
{"break" ,tok_break },
{"continue",tok_continue },
{"return" ,tok_ret },
{"if" ,tok_if },
{"elsif" ,tok_elsif },
{"else" ,tok_else },
{"nil" ,tok_nil },
{"(" ,tok_lcurve },
{")" ,tok_rcurve },
{"[" ,tok_lbracket },
{"]" ,tok_rbracket },
{"{" ,tok_lbrace },
{"}" ,tok_rbrace },
{";" ,tok_semi },
{"and" ,tok_and },
{"or" ,tok_or },
{"," ,tok_comma },
{"." ,tok_dot },
{"..." ,tok_ellipsis },
{"?" ,tok_quesmark },
{":" ,tok_colon },
{"+" ,tok_add },
{"-" ,tok_sub },
{"*" ,tok_mult },
{"/" ,tok_div },
{"~" ,tok_link },
{"!" ,tok_not },
{"=" ,tok_eq },
{"+=" ,tok_addeq },
{"-=" ,tok_subeq },
{"*=" ,tok_multeq },
{"/=" ,tok_diveq },
{"~=" ,tok_lnkeq },
{"==" ,tok_cmpeq },
{"!=" ,tok_neq },
{"<" ,tok_less },
{"<=" ,tok_leq },
{">" ,tok_grt },
{">=" ,tok_geq },
{nullptr ,0 }
};
struct token
{
uint32_t line;
uint32_t column;
uint32_t type;
std::string str;
token(uint32_t l=0,uint32_t c=0,uint32_t t=tok_null,const std::string& s=""):str(s)
{
line=l;
column=c;
type=t;
}
};
class nasal_lexer
{
private:
uint32_t line;
uint32_t column;
uint32_t ptr;
nasal_err& nerr;
std::string res;
std::vector<token> tokens;
uint32_t get_type(const std::string&);
void die(std::string info){nerr.err("lexer",line,column,info);};
void open(const std::string&);
std::string utf8_gen();
std::string id_gen();
std::string num_gen();
std::string str_gen();
public:
nasal_lexer(nasal_err& e):line(0),column(0),ptr(0),nerr(e){}
void scan(const std::string&);
void print();
const std::vector<token>& get_tokens() const {return tokens;}
};
void nasal_lexer::open(const std::string& file)
{
struct stat buffer;
if(stat(file.c_str(),&buffer)==0 && !S_ISREG(buffer.st_mode))
{
nerr.err("lexer","<"+file+"> is not a regular file.");
res="";
return;
}
std::ifstream fin(file,std::ios::binary);
if(fin.fail())
nerr.err("lexer","failed to open <"+file+">.");
else
nerr.load(file);
std::stringstream ss;
ss<<fin.rdbuf();
res=ss.str();
}
uint32_t nasal_lexer::get_type(const std::string& tk_str)
{
for(int i=0;token_table[i].str;++i)
if(tk_str==token_table[i].str)
return token_table[i].tok_type;
return tok_null;
}
std::string nasal_lexer::utf8_gen()
{
std::string str="";
while(ptr<res.size() && res[ptr]<0)
{
std::string tmp="";
uint32_t nbytes=utf8_hdchk(res[ptr]);
if(nbytes)
{
tmp+=res[ptr++];
for(uint32_t i=0;i<nbytes;++i,++ptr)
if(ptr<res.size() && (res[ptr]&0xc0)==0x80)
tmp+=res[ptr];
if(tmp.length()!=1+nbytes)
die("invalid utf-8 character here");
str+=tmp;
++column;
}
else
++ptr;
}
return str;
}
std::string nasal_lexer::id_gen()
{
std::string str="";
while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr])))
{
if(res[ptr]<0) // utf-8
str+=utf8_gen();
else // ascii
{
str+=res[ptr++];
++column;
}
}
return str;
}
std::string nasal_lexer::num_gen()
{
// generate hex number
if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='x')
{
std::string str="0x";
ptr+=2;
while(ptr<res.size() && HEX(res[ptr]))
str+=res[ptr++];
column+=str.length();
if(str.length()<3)// "0x"
die("invalid number:"+str);
return str;
}
// generate oct number
else if(ptr+1<res.size() && res[ptr]=='0' && res[ptr+1]=='o')
{
std::string str="0o";
ptr+=2;
while(ptr<res.size() && OCT(res[ptr]))
str+=res[ptr++];
column+=str.length();
if(str.length()<3)// "0o"
die("invalid number:"+str);
return str;
}
// generate dec number
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
std::string str="";
while(ptr<res.size() && DIGIT(res[ptr]))
str+=res[ptr++];
if(ptr<res.size() && res[ptr]=='.')
{
str+=res[ptr++];
while(ptr<res.size() && DIGIT(res[ptr]))
str+=res[ptr++];
// "xxxx." is not a correct number
if(str.back()=='.')
{
column+=str.length();
die("invalid number:"+str);
return "0";
}
}
if(ptr<res.size() && (res[ptr]=='e' || res[ptr]=='E'))
{
str+=res[ptr++];
if(ptr<res.size() && (res[ptr]=='-' || res[ptr]=='+'))
str+=res[ptr++];
while(ptr<res.size() && DIGIT(res[ptr]))
str+=res[ptr++];
// "xxxe(-|+)" is not a correct number
if(str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+')
{
column+=str.length();
die("invalid number:"+str);
return "0";
}
}
column+=str.length();
return str;
}
std::string nasal_lexer::str_gen()
{
std::string str="";
char begin=res[ptr];
++column;
while(++ptr<res.size() && res[ptr]!=begin)
{
++column;
if(res[ptr]=='\n')
{
column=0;
++line;
}
if(res[ptr]=='\\' && ptr+1<res.size())
{
++column;
++ptr;
switch(res[ptr])
{
case '0': str+='\0'; break;
case 'a': str+='\a'; break;
case 'b': str+='\b'; break;
case 'e': str+='\e'; break;
case 't': str+='\t'; break;
case 'n': str+='\n'; break;
case 'v': str+='\v'; break;
case 'f': str+='\f'; break;
case 'r': str+='\r'; break;
case '?': str+='\?'; break;
case '\\':str+='\\'; break;
case '\'':str+='\''; break;
case '\"':str+='\"'; break;
default: str+=res[ptr];break;
}
continue;
}
str+=res[ptr];
}
// check if this string ends with a " or '
if(ptr++>=res.size())
{
die("get EOF when generating string.");
return str;
}
++column;
if(begin=='`' && str.length()!=1)
die("\'`\' is used for string that includes one character.");
return str;
}
void nasal_lexer::scan(const std::string& file)
{
line=1;
column=0;
ptr=0;
open(file);
std::string str;
while(ptr<res.size())
{
while(ptr<res.size() && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r'))// || res[ptr]<0))
{
// these characters will be ignored, and '\n' will cause ++line
++column;
if(res[ptr++]=='\n')
{
++line;
column=0;
}
}
if(ptr>=res.size()) break;
if(ID(res[ptr]))
{
str=id_gen();
uint32_t type=get_type(str);
tokens.push_back({line,column,type?type:tok_id,str});
}
else if(DIGIT(res[ptr]))
{
str=num_gen(); // make sure column is correct
tokens.push_back({line,column,tok_num,str});
}
else if(STR(res[ptr]))
{
str=str_gen(); // make sure column is correct
tokens.push_back({line,column,tok_str,str});
}
else if(SINGLE_OPERATOR(res[ptr]))
{
str=res[ptr];
++column;
uint32_t type=get_type(str);
if(!type)
die("invalid operator:"+str);
tokens.push_back({line,column,type,str});
++ptr;
}
else if(res[ptr]=='.')
{
str=".";
if(ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.')
str+="..";
ptr+=str.length();
column+=str.length();
tokens.push_back({line,column,get_type(str),str});
}
else if(CALC_OPERATOR(res[ptr]))
{
// get calculation operator
str=res[ptr++];
if(ptr<res.size() && res[ptr]=='=')
str+=res[ptr++];
column+=str.length();
tokens.push_back({line,column,get_type(str),str});
}
else if(NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
while(++ptr<res.size() && res[ptr]!='\n');
else
{
++column;
++ptr;
die("unknown character.");
}
}
tokens.push_back({line,column,tok_eof,"eof"});
res="";
nerr.chkerr();
}
void nasal_lexer::print()
{
for(auto& tok:tokens)
std::cout<<"("<<tok.line<<" | "<<rawstr(tok.str)<<")\n";
}
#endif

70
nasal_opt.h Normal file
View File

@@ -0,0 +1,70 @@
#ifndef __NASAL_OPT_H__
#define __NASAL_OPT_H__
void const_str(nasal_ast& root)
{
auto& vec=root.child();
root.set_str(vec[0].str()+vec[1].str());
root.child().clear();
root.set_type(ast_str);
}
void const_num(nasal_ast& root)
{
auto& vec=root.child();
double res;
switch(root.type())
{
case ast_add: res=vec[0].num()+vec[1].num(); break;
case ast_sub: res=vec[0].num()-vec[1].num(); break;
case ast_mult:res=vec[0].num()*vec[1].num(); break;
case ast_div: res=vec[0].num()/vec[1].num(); break;
case ast_less:res=vec[0].num()<vec[1].num(); break;
case ast_leq: res=vec[0].num()<=vec[1].num();break;
case ast_grt: res=vec[0].num()>vec[1].num(); break;
case ast_geq: res=vec[0].num()>=vec[1].num();break;
}
// inf and nan will cause number hashmap error in codegen
if(std::isinf(res) || std::isnan(res))
return;
root.set_num(res);
root.child().clear();
root.set_type(ast_num);
}
void calc_const(nasal_ast& root)
{
auto& vec=root.child();
for(auto& i:vec)
calc_const(i);
if(vec.size()==1 && root.type()==ast_neg && vec[0].type()==ast_num)
{
double res=-vec[0].num();
root.set_num(res);
root.child().clear();
root.set_type(ast_num);
return;
}
if(vec.size()!=2)
return;
if(root.type()!=ast_add &&
root.type()!=ast_sub &&
root.type()!=ast_mult &&
root.type()!=ast_div &&
root.type()!=ast_link &&
root.type()!=ast_less &&
root.type()!=ast_leq &&
root.type()!=ast_grt &&
root.type()!=ast_geq)
return;
if(root.type()==ast_link && vec[0].type()==ast_str && vec[1].type()==ast_str)
const_str(root);
else if(root.type()!=ast_link && vec[0].type()==ast_num && vec[1].type()==ast_num)
const_num(root);
}
void optimize(nasal_ast& root)
{
for(auto& i:root.child())
calc_const(i);
}
#endif

File diff suppressed because it is too large Load Diff

1477
nasal_vm.h

File diff suppressed because it is too large Load Diff

BIN
pic/benchmark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
pic/mandelbrot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

26
stl/file.nas Normal file
View File

@@ -0,0 +1,26 @@
# lib file.nas
# ValKmjolnir 2022/3/6
import("lib.nas");
var file={
SEEK_SET:io.SEEK_SET,
SEEK_CUR:io.SEEK_CUR,
SEEK_END:io.SEEK_END,
new: func(filename,mode="r"){
var fd=io.open(filename,mode);
return {
close: func(){io.close(fd);},
read: func(len){
var buf=mut("");
io.read(fd,buf,len);
return buf;
},
write: func(str){return io.write(fd,str);},
seek: func(pos,whence){return io.seek(fd,pos,whence);},
tell: func(){return io.tell(fd);},
readln: func(){return io.readln(fd);},
stat: func(){return io.stat(filename);},
eof: func(){return io.eof(fd);}
};
}
};

View File

@@ -1,144 +1,469 @@
var import=func(filename)
{
# lib.nas
# import is used to link another file, this lib function will do nothing.
# because nasal_import will recognize this and link files before generating bytecode.
var import=func(filename){
return __builtin_import(filename);
}
var print=func(elems...)
{
# print is used to print all things in nasal, try and see how it works.
# this function uses std::cout/printf to output logs.
var print=func(elems...){
return __builtin_print(elems);
};
var println=func(elems...)
{
}
# append is used to add values into a vector.
var append=func(vec,elems...){
return __builtin_append(vec,elems);
}
# setsize is used to change the size of vector.
# if the size is larger than before,
# this function will fill vm_nil into uninitialized space.
var setsize=func(vec,size){
return __builtin_setsize(vec,size);
}
# system has the same use in C.
var system=func(str){
return __builtin_system(str);
}
# input uses std::cin and returns what we input.
var input=func(){
return __builtin_input();
}
# split a string by separator for example:
# split("ll","hello world") -> ["he","o world"]
# this function will return a vector.
var split=func(separator,str){
return __builtin_split(separator,str);
}
# rand has the same function as the rand in C
# if seed is nil, it will return the random number.
# if seed is not nil, it will be initialized by this seed.
var rand=func(seed=nil){
return __builtin_rand(seed);
}
# id will return the pointer of an gc-object.
# if this object is not managed by gc, it will return 0.
var id=func(object){
return __builtin_id(object);
}
# int will get the integer of input number.
# but carefully use it, because int has range between -2147483648~2147483647
var int=func(val){
return __builtin_int(val);
}
# floor will get the integral number of input argument
# which is less than or equal to this argument
var floor=func(val){
return __builtin_floor(val);
}
# abort using std::abort
var abort=func(){
__builtin_abort();
}
# abs gets absolute number.
var abs=func(n){
return n>0?n:-n;
}
# num will change all the other types into number.
# mostly used to change a numerable string.
var num=func(val){
return __builtin_num(val);
}
# pop used to pop the last element in a vector.
# this function will return the value that poped if vector has element(s).
# if the vector is empty, it will return nil.
var pop=func(vec){
return __builtin_pop(vec);
}
# str is used to change number into string.
var str=func(num){
return __builtin_str(num);
}
# size can get the size of a string/vector/hashmap.
# in fact it can also get the size of number, and the result is the number itself.
# so don't do useless things, though it really works.
var size=func(object){
return __builtin_size(object);
}
# contains is used to check if a key exists in a hashmap/dict.
var contains=func(hash,key){
return __builtin_contains(hash,key);
}
# delete is used to delete a pair in a hashmap/dict by key.
var delete=func(hash,key){
return __builtin_delete(hash,key);
}
# keys is used to get all keys in a hashmap/dict.
# this function will return a vector.
var keys=func(hash){
return __builtin_keys(hash);
}
# time has the same function in C.
var time=func(begin){
return __builtin_time(begin);
}
var systime=func(){
return time(0);
}
# die is a special native function.
# use it at where you want the program to crash immediately.
var die=func(str){
return __builtin_die(str);
}
# find will give the first position of the needle in haystack
var find=func(needle,haystack){
return __builtin_find(needle,haystack);
}
# typeof is used to get the type of an object.
# this function returns a string.
var typeof=func(object){
return __builtin_type(object);
}
# subvec is used to get part of a vector
var subvec=func(vec,begin,length=nil){
return vec[begin:(length==nil?nil:begin+length-1)];
}
# substr will get the sub-string.
# it gets the string, the begin index and sub-string's length as arguments.
var substr=func(str,begin,len){
return __builtin_substr(str,begin,len);
}
# streq is used to compare if two strings are the same.
var streq=func(a,b){
return __builtin_streq(a,b);
}
# left is used to get the sub-string like substr.
# but the begin index is 0.
var left=func(str,len){
return __builtin_left(str,len);
}
# right i used to get the sub-string like substr.
# but the begin index is strlen-len.
var right=func(str,len){
return __builtin_right(str,len);
}
# cmp is used to compare two strings.
# normal string will not be correctly compared by operators < > <= >=
# because these operators will turn strings into numbers then compare.
var cmp=func(a,b){
return __builtin_cmp(a,b);
}
# chr is used to get the character by ascii-number.
# for example chr(65) -> 'A'
var chr=func(code){
return __builtin_chr(code);
}
# mut is used to change unmutable strings to mutable.
var mut=func(str){
return str~"";
}
# srand wraps up rand, using time(0) as the seed.
var srand=func(){
rand(time(0));
return 0;
}
# values() gets all values in a hash.
var values=func(hash){
return __builtin_values(hash);
}
# println has the same function as print.
# but it will output a '\n' after using print.
var println=func(elems...){
__builtin_print(elems);
elems=['\n'];
return __builtin_print(elems);
}
var append=func(vec,elems...)
{
return __builtin_append(vec,elems);
var isfunc=func(f){
return typeof(f)=="func";
}
var setsize=func(vec,size)
{
return __builtin_setsize(vec,size);
var isghost=func(g){
die("this runtime has no ghost object");
return 0;
}
var system=func(str)
{
return __builtin_system(str);
var ishash=func(h){
return typeof(h)=="hash";
}
var input=func()
{
return __builtin_input();
var isint=func(x){
return x==floor(x);
}
var sleep=func(duration)
{
return __builtin_sleep(duration);
var isnum=func(x){
return typeof(x)=="num" or !math.isnan(num(x));
}
var split=func(deli,str)
{
return __builtin_split(deli,str);
var isscalar=func(s){
var t=typeof(s);
return (t=="num" or t=="str")?1:0;
}
var rand=func(seed=nil)
{
return __builtin_rand(seed);
var isstr=func(s){
return typeof(s)=="str";
}
var id=func(object)
{
return __builtin_id(object);
var isvec=func(v){
return typeof(v)=="vec";
}
var int=func(val)
{
return __builtin_int(val);
# get the index of val in the vec
var vecindex=func(vec,val){
forindex(var i;vec)
if(val==vec[i])
return i;
return nil;
}
var num=func(val)
{
return __builtin_num(val);
# check if the object is an instance of the class
var isa=func(object,class){
if(!contains(object,"parents") or typeof(object.parents)!="vec")
return 0;
foreach(var elem;object.parents)
if(elem==class)
return 1;
return 0;
}
var pop=func(vec)
{
return __builtin_pop(vec);
# assert aborts when condition is not true
var assert=func(condition,message="assertion failed!"){
if(condition)
return 1;
die(message);
}
var str=func(num)
{
return __builtin_str(num);
}
var size=func(object)
{
return __builtin_size(object);
}
var contains=func(hash,key)
{
return __builtin_contains(hash,key);
}
var delete=func(hash,key)
{
return __builtin_delete(hash,key);
}
var keys=func(hash)
{
return __builtin_keys(hash);
}
var time=func(begin_time)
{
return __builtin_time(begin_time);
}
var die=func(str)
{
return __builtin_die(str);
}
var typeof=func(object)
{
return __builtin_type(object);
}
var substr=func(str,begin,len)
{
return __builtin_substr(str,begin,len);
}
var streq=func(a,b)
{
return __builtin_streq(a,b);
}
var left=func(str,len)
{
return __builtin_left(str,len);
}
var right=func(str,len)
{
return __builtin_right(str,len);
}
var cmp=func(a,b)
{
return __builtin_cmp(a,b);
}
var chr=func(code)
{
return __builtin_chr(code);
# md5
var md5=func(str){
return __builtin_md5(str);
}
var io=
{
fin: func(filename){return __builtin_fin(filename);},
fout:func(filename,str){return __builtin_fout(filename,str);}
SEEK_SET:0,
SEEK_CUR:1,
SEEK_END:2,
# get content of a file by filename. returns a string.
fin: func(filename){return __builtin_fin(filename);},
# input a string as the content of a file.
fout: func(filename,str){return __builtin_fout(filename,str);},
# same as C fopen. open file and get the FILE*.
open: func(filename,mode="r"){return __builtin_open(filename,mode);},
# same as C fclose. close file by FILE*.
close: func(filehandle){return __builtin_close(filehandle);},
# same as C fread. read file by FILE*.
# caution: buf must be a mutable string.use mut("") to get an empty mutable string.
read: func(filehandle,buf,len){return __builtin_read(filehandle,buf,len);},
# same as C fwrite. write file by FILE*.
write: func(filehandle,str){return __builtin_write(filehandle,str);},
# same as C fseek. seek place by FILE*.
seek: func(filehandle,pos,whence){return __builtin_seek(filehandle,pos,whence);},
# same as C ftell.
tell: func(filehandle){return __builtin_tell(filehandle);},
# read file by lines. use FILE*.
# get nil if EOF
readln:func(filehandle){return __builtin_readln(filehandle);},
# same as C stat.
stat: func(filename){return __builtin_stat(filename);},
# same as C feof. check if FILE* gets the end of file(EOF).
eof: func(filehandle){return __builtin_eof(filehandle);}
};
# get file status. using data from io.stat
var fstat=func(filename){
var s=io.stat(filename);
return {
st_dev: s[0],
st_ino: s[1],
st_mode: s[2],
st_nlink:s[3],
st_uid: s[4],
st_gid: s[5],
st_rdev: s[6],
st_size: s[7],
st_atime:s[8],
st_mtime:s[9],
st_ctime:s[10]
};
}
# functions that do bitwise calculation.
# carefully use it, all the calculations are based on integer.
var bits=
{
# xor
bitxor: func(a,b){return __builtin_xor(a,b); },
# and
bitand: func(a,b){return __builtin_and(a,b); },
# or
bitor: func(a,b){return __builtin_or(a,b); },
# nand
bitnand: func(a,b){return __builtin_nand(a,b);},
bitnot: func(a) {return __builtin_not(a); }
# not
bitnot: func(a) {return __builtin_not(a); },
# get bit data from a special string. for example:
# bits.fld(s,0,3);
# if s stores 10100010(162)
# will get 101(5).
fld: func(str,startbit,len){return __builtin_fld;},
# get sign-extended data from a special string. for example:
# bits.sfld(s,0,3);
# if s stores 10100010(162)
# will get 101(5) then this will be signed extended to
# 11111101(-3).
sfld: func(str,startbit,len){return __builtin_sfld;},
# set value into a special string to store it. little-endian, for example:
# bits.setfld(s,0,8,69);
# set 01000101(69) to string will get this:
# 10100010(162)
# so s[0]=162.
setfld: func(str,startbit,len,val){return __builtin_setfld;},
# get a special string filled by '\0' to use in setfld.
buf: func(len){return __builtin_buf;}
};
# mostly used math functions and special constants, you know.
var math=
{
e: 2.7182818284590452354,
pi: 3.14159265358979323846264338327950288,
inf: 1/0,
nan: 0/0,
abs: func(x) {return x>0?x:-x; },
floor: func(x) {return __builtin_floor(x); },
pow: func(x,y){return __builtin_pow(x,y); },
sin: func(x) {return __builtin_sin(x); },
cos: func(x) {return __builtin_cos(x); },
tan: func(x) {return __builtin_tan(x); },
exp: func(x) {return __builtin_exp(x); },
exp: func(x) {return __builtin_exp(x); },
lg: func(x) {return __builtin_lg(x); },
ln: func(x) {return __builtin_ln(x); },
sqrt: func(x) {return __builtin_sqrt(x); },
atan2: func(x,y){return __builtin_atan2(x,y);}
atan2: func(x,y){return __builtin_atan2(x,y);},
isnan: func(x) {return __builtin_isnan(x); },
max: func(x,y){return x>y?x:y; },
min: func(x,y){return x<y?x:y; }
};
var D2R=math.pi/180;
var unix=
{
pipe: func(){return __builtin_pipe;},
fork: func(){return __builtin_fork;},
dup2: func(fd0,fd1){die("not supported yet");},
exec: func(filename,argv,envp){die("not supported yet");},
waitpid: func(pid,nohang=0){return __builtin_waitpid;},
isdir: func(path){return bits.bitand(io.stat(path)[2],0x4000);}, # S_IFDIR 0x4000
isfile: func(path){return bits.bitand(io.stat(path)[2],0x8000);}, # S_IFREG 0x8000
opendir: func(path){return __builtin_opendir;},
readdir: func(handle){return __builtin_readdir;},
closedir: func(handle){return __builtin_closedir;},
time: func(){return time(0);},
sleep: func(secs){return __builtin_sleep(secs);},
chdir: func(path){return __builtin_chdir(path);},
environ: func(){return __builtin_environ();},
getcwd: func(){return __builtin_getcwd();},
getenv: func(envvar){return __builtin_getenv(envvar);}
};
# dylib is the core hashmap for developers to load their own library.
# for safe using dynamic library, you could use 'module' in stl/module.nas
var dylib=
{
# open dynamic lib.
dlopen: func(libname){return __builtin_dlopen;},
# load symbol from an open dynamic lib.
dlsym: func(lib,sym){return __builtin_dlsym; },
# close dynamic lib, this operation will make all the symbols loaded from it invalid.
dlclose: func(lib){return __builtin_dlclose; },
# call the loaded symbol.
dlcall: func(funcptr,args...){return __builtin_dlcall}
};
# os is used to use or get some os-related info/functions.
# windows/macOS/linux are supported.
var os=
{
# get a string that tell which os it runs on.
platform: func(){return __builtin_platform;}
};
# runtime gives us some functions that we could manage it manually.
var runtime=
{
# do garbage collection manually.
# carefully use it because using it frequently may make program running slower.
gc: func(){return __builtin_gc;}
};
# important global constants
var D2R=math.pi/180;
var FPS2KT=0.5925;
var FT2M=0.3048;
var GAL2L=3.7854;
var IN2M=0.0254;
var KG2LB=2.2046;
var KT2FPS=1.6878;
var KT2MPS=0.5144;
var L2GAL=0.2642;
var LB2KG=0.4536;
var M2FT=3.2808;
var M2IN=39.3701;
var M2NM=0.00054;
var MPS2KT=1.9438;
var NM2M=1852;
var R2D=180/math.pi;
# functions that not supported in this runtime:
var bind=func(function,locals,outer_scope=nil){
die("this runtime does not support bind");
}
var call=func(function,args=nil,_me=nil,locals=nil,error=nil){
die("this runtime does not support call");
}
var caller=func(level=1){
die("this runtime does not support caller");
}
var closure=func(function,level=1){
die("this runtime uses \"vm_upval\" instead of \"vm_hash\" as the closure");
}
var compile=func(code,filename="<compile>"){
die("this runtime uses static code generator");
}

View File

@@ -2,72 +2,51 @@
# valkmjolnir 2021/3/31
var list=func()
{
var _={begin:nil,end:nil};
return
{
push_back:func(elem)
{
var (begin,end)=(nil,nil);
return{
push_back:func(elem){
var tmp={elem:elem,prev:nil,next:nil};
if(_.end!=nil)
{
_.end.next=tmp;
tmp.prev=_.end;
_.end=tmp;
if(end!=nil){
end.next=tmp;
tmp.prev=end;
end=tmp;
}
else
{
_.begin=tmp;
_.end=tmp;
}
return;
begin=end=tmp;
},
push_front:func(elem)
{
push_front:func(elem){
var tmp={elem:elem,prev:nil,next:nil};
if(_.begin!=nil)
{
_.begin.prev=tmp;
tmp.next=_.begin;
_.begin=tmp;
if(begin!=nil){
begin.prev=tmp;
tmp.next=begin;
begin=tmp;
}
else
{
_.begin=tmp;
_.end=tmp;
}
return;
begin=end=tmp;
},
pop_back:func()
{
if(_.end!=nil)
_.end=_.end.prev;
if(_.end==nil)
_.begin=nil;
pop_back:func(){
if(end!=nil)
end=end.prev;
if(end==nil)
begin=nil;
else
_.end.next=nil;
return;
end.next=nil;
},
pop_front:func()
{
if(_.begin!=nil)
_.begin=_.begin.next;
if(_.begin==nil)
_.end=nil;
pop_front:func(){
if(begin!=nil)
begin=begin.next;
if(begin==nil)
end=nil;
else
_.begin.prev=nil;
return;
begin.prev=nil;
},
front:func()
{
if(_.begin!=nil)
return _.begin.elem;
return nil;
front:func(){
if(begin!=nil)
return begin.elem;
},
back:func()
{
if(_.end!=nil)
return _.end.elem;
return nil;
back:func(){
if(end!=nil)
return end.elem;
},
};
}

43
stl/module.nas Normal file
View File

@@ -0,0 +1,43 @@
# lib module.nas
# ValKmjolnir 2022/3/5
# this provides safe usage of dylib
# when dylib is closed,
# all the invalid functions cannot be called
var module_call_func=func(fptr,args){
return __builtin_dlcall;
}
var extern={
new: func(fptr){
var isopen=1;
return {
close:func(){isopen=0;},
call:func(args...){
return (!isopen)?
nil:
module_call_func(fptr,args);
}
};
}
};
var module={
new: func(name){
var lib=dylib.dlopen(name);
var f={};
return {
get:func(symbol){
if(contains(f,symbol))
return f[symbol];
var fp=extern.new(dylib.dlsym(lib,symbol));
f[symbol]=fp;
return fp;
},
close: func(){
foreach(var i;keys(f))
f[i].close();
dylib.dlclose(lib);
}
};
}
};

View File

@@ -2,45 +2,35 @@
# valkmjolnir 2021/3/31
var queue=func()
{
var _={begin:nil,end:nil};
return
{
push:func(elem)
{
var new_node=
{
var (begin,end)=(nil,nil);
return{
push:func(elem){
var new_node={
elem:elem,
next:nil
};
if(_.begin==nil)
_.begin=_.end=new_node;
else
{
_.end.next=new_node;
_.end=new_node;
if(begin==nil)
begin=end=new_node;
else{
end.next=new_node;
end=new_node;
}
return;
},
pop:func()
{
if(_.begin!=nil)
_.begin=_.begin.next;
if(_.begin==nil)
_.end=nil;
pop:func(){
if(begin!=nil)
begin=begin.next;
if(begin==nil)
end=nil;
},
front:func()
{
if(_.begin!=nil)
return _.begin.elem;
return nil;
front:func(){
if(begin!=nil)
return begin.elem;
},
clear:func()
{
_.begin=_.end=nil;
clear:func(){
begin=end=nil;
},
empty:func()
{
return _.begin==nil;
empty:func(){
return begin==nil;
}
};
}

28
stl/result.nas Normal file
View File

@@ -0,0 +1,28 @@
import("lib.nas");
var ResultTrait={
Ok:func(val){
me.ok=val;
me.flag=0;
return me;
},
Err:func(info){
me.err=info;
me.flag=1;
return me;
},
unwrap:func(){
if(me.flag)
die(me.err);
return me.ok;
}
};
var Result=func(){
return{
ok:nil,
err:"",
flag:1,
parents:[ResultTrait]
};
};

View File

@@ -3,9 +3,7 @@
var sort=func(vec,left,right,cmp=func(a,b){return a<=b;})
{
if(left>=right) return nil;
var L=left;
var R=right;
var tmp=vec[L];
var (L,R,tmp)=(left,right,vec[left]);
while(left<right)
{
while(left<right and cmp(tmp,vec[right]))
@@ -13,14 +11,9 @@ var sort=func(vec,left,right,cmp=func(a,b){return a<=b;})
while(left<right and cmp(vec[left],tmp))
left+=1;
if(left!=right)
{
var t=vec[left];
vec[left]=vec[right];
vec[right]=t;
}
(vec[left],vec[right])=(vec[right],vec[left]);
}
vec[L]=vec[left];
vec[left]=tmp;
(vec[L],vec[left])=(vec[left],tmp);
sort(vec,L,left-1,cmp);
sort(vec,left+1,R,cmp);
return nil;

View File

@@ -2,35 +2,24 @@
# valkmjolnir 2021/3/31
var stack=func()
{
var _={next:nil};
return
{
push:func(elem)
{
_.next={elem:elem,next:_.next};
return;
var next=nil;
return{
push:func(elem){
next={elem:elem,next:next};
},
pop:func()
{
var tmp=_.next;
if(tmp!=nil)
_.next=tmp.next;
return;
pop:func(){
if(next!=nil)
next=next.next;
},
top:func()
{
var tmp=_.next;
if(tmp!=nil)
return tmp.elem;
return nil;
top:func(){
if(next!=nil)
return next.elem;
},
clear:func()
{
_.next=nil;
clear:func(){
next=nil;
},
empty:func()
{
return _.next==nil;
empty:func(){
return next==nil;
}
};
}

View File

@@ -1,4 +1,3 @@
import("lib.nas");
var char_ttf=[
[" "," "," "," "," "," "],
[" ████╗"," ██╔██║"," ██╔╝██║"," ███████║","██╔═══██║","╚═╝ ╚═╝"],
@@ -114,9 +113,43 @@ var curve4=func()
}
return;
}
var curve5=func(){
for(var i=0;i<=9;i+=1)
println(i,"\e["~i~"mh \e[0m");
for(var i=30;i<=37;i+=1)
println(i,"\e["~i~"mh \e[0m");
for(var i=40;i<=47;i+=1)
println(i,"\e["~i~"mh \e[0m");
for(var i=90;i<=97;i+=1)
println(i,"\e["~i~"mh \e[0m");
for(var i=100;i<=107;i+=1)
println(i,"\e["~i~"mh \e[0m");
}
var curve6=func(){
var shadow=["m░\e[0m","m▒\e[0m","m▓\e[0m","m█\e[0m","m▀\e[0m","m▄\e[0m","m▐\e[0m","m▌\e[0m"];
var front=[
"30","31","32","33","34","35","36","37",
"90","91","92","93","94","95","96","97"
];
var back=[
"40","41","42","43","44","45","46","47",
"100","101","102","103","104","105","106","107"
];
rand(time(0));
for(var i=0;i<15;i+=1){
for(var j=0;j<45;j+=1)
print("\e["~front[16*rand()]~";"~back[16*rand()]~shadow[8*rand()]);
print('\n');
}
}
if(os.platform()=="windows")
system("chcp 65001");
trans_ttf("just for test");
trans_ttf(" ValKmjolnir ");
trans_ttf("just for fun");
curve1();
curve2();
curve3();
curve4();
curve4();
curve5();
curve6();

View File

@@ -1,6 +1,5 @@
# Road check and auto pilot by ValKmjolnir
import("lib.nas");
import("props.nas");
import("test/props_sim.nas");
var dt=0.01;
var intergral=0;
var derivative=0;

View File

@@ -1,5 +1,3 @@
import("lib.nas");
var mandelbrot=
"[A mandelbrot set fractal viewer in brainf*** written by Erik Bosman]
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
@@ -149,91 +147,80 @@ var mandelbrot=
var paper=[];
var (ptr,pc)=(0,0);
var (code,inum,stack)=(nil,nil,nil);
var (code,inum,stack)=([],[],[]);
var (add,mov,jt,jf,in,out)=(0,1,2,3,4,5);
var func_table=[
func(){paper[ptr]+=inum[pc];return;},
func(){ptr+=inum[pc];return;},
func(){if(paper[ptr])pc=inum[pc];return;},
func(){if(!paper[ptr])pc=inum[pc];return;},
func(){paper[ptr]=input()[0];return;},
func(){print(chr(paper[ptr]));return;}
var funcs=[
func{paper[ptr]+=inum[pc];},
func{ptr+=inum[pc];},
func{if(paper[ptr])pc=inum[pc];},
func{if(!paper[ptr])pc=inum[pc];},
func{paper[ptr]=input()[0];},
func{print(chr(paper[ptr]));}
];
var bf=func(program)
{
var bf=func(program){
setsize(paper,131072);
(ptr,code,inum,stack)=(0,[],[],[]);
var len=size(program);
for(var i=0;i<len;i+=1)
{
for(var i=0;i<len;i+=1){
var c=chr(program[i]);
if(c=='+' or c=='-')
{
append(code,func_table[add]);
if(c=='+' or c=='-'){
append(code,add);
append(inum,0);
for(;i<len;i+=1)
{
for(;i<len;i+=1){
if(chr(program[i])=='+')
inum[-1]+=1;
elsif(chr(program[i])=='-')
inum[-1]-=1;
else
{
elsif(chr(program[i])!='\n'){
i-=1;
break;
}
}
}
elsif(c=='<' or c=='>')
{
append(code,func_table[mov]);
elsif(c=='<' or c=='>'){
append(code,mov);
append(inum,0);
for(;i<len;i+=1)
{
for(;i<len;i+=1){
if(chr(program[i])=='>')
inum[-1]+=1;
elsif(chr(program[i])=='<')
inum[-1]-=1;
else
{
elsif(chr(program[i])!='\n'){
i-=1;
break;
}
}
}
elsif(c==',')
{
append(code,func_table[in]);
elsif(c==','){
append(code,in);
append(inum,0);
}
elsif(c=='.')
{
append(code,func_table[out]);
elsif(c=='.'){
append(code,out);
append(inum,0);
}
elsif(c=='[')
{
append(code,func_table[jf]);
elsif(c=='['){
append(code,jf);
append(inum,0);
append(stack,size(code)-1);
}
elsif(c==']')
{
elsif(c==']'){
if(!size(stack))
die("lack [");
var label=pop(stack);
append(code,func_table[jt]);
append(code,jt);
append(inum,label-1);
inum[label]=size(code)-2;
}
}
if(size(stack))
if(size(stack)){
die("lack ]");
return;
}
len=size(code);
for(pc=0;pc<len;pc+=1)
code[pc]();
funcs[code[pc]]();
return;
}

242
test/bfcolored.nas Normal file
View File

@@ -0,0 +1,242 @@
var mandelbrot=
"[A mandelbrot set fractal viewer in brainf*** written by Erik Bosman]
+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+
<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>
>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>
>>>>>[-]+<<<<<<++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<+++++++[-[->>>
>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[[-]>>>>>>[>>>>>
>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>
[>>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<
<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>+++++++++++++++[[
>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[
>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[
-<<+>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<
<<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<
[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>
>>>>[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+
<<<<<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>
>>>>>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<
+>>>>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<
<]<+<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<
<<<]>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->
>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<
<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]<<<<<<<[->+>>>-<<<<]>>>>>>>>>+++++++++++++++++++
+++++++>>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>[<<<<<<<+<[-<+>>>>+<<[-]]>[-<<[->+>>>-
<<<<]>>>]>>>>>>>>>>>>>[>>[-]>[-]>[-]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>>>>>>[>>>>>
[-<<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>[-<<<<<<<<
<+>>>>>>>>>]>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>>]+>[-
]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>>>>>>>]<<<
<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+>>]<
<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[->>>>
>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-]<->>>
[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[>>>>>>[-<
<<<<+>>>>>]<<<<<[->>>>>+<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>+>>>>>>>>
]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>++++++++
+++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-<<<<<<<+
>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[
-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>>]>[-<<<<<<[->>>>>+<++<<<<]>>>>>[-<
<<<<+>>>>>]<->+>]<[->+<]<<<<<[->>>>>+<<<<<]>>>>>>[-]<<<<<<+>>>>[-<<<<->>>>]+<<<<
[->>>>->>>>>[>>[-<<->>]+<<[->>->[-<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]
+>>>>>>[>>>>>>>>>]>+<]]+>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<<<<<<<<<<[<<<<<
<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<
[<<<<<<<<<]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<
<<<+<[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<
<<<<<<<<<<]>>>>[-]<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+<]>>>>>>>>]<<<
<<<<<+<[>[->>>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>[->>>>+<<<<]>]<[->>>>-<<<<<<<
<<<<<<<+>>>>>>>>>>]<]>>[->>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>>+<<<<
]<<<<<<<<<<<]>>>>>>+<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>>>>>>>>>]<<<<<<<<<
[>[->>>>>+<<<<[->>>>-<<<<<<<<<<<<<<+>>>>>>>>>>>[->>>+<<<]<]>[->>>-<<<<<<<<<<<<<<
+>>>>>>>>>>>]<<]>[->>>>+<<<[->>>-<<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>>+<<<]<<<<<<<
<<<<<]]>[-]>>[-]>[-]>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<
<<<+>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[
[>>>>>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>
[-<<+>>]<<[->>+>+<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<
<[>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[
>[-]<->>>[-<<<+>[<->-<<<<<<<+>>>>>>>]<[->+<]>>>]<<[->>+<<]<+<<<<<<<<<]>>>>>>>>>[
>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>]>
>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>[-]>>>>+++++++++++++++[[>>>>>>>>>]<<<<<<<<<-<<<<<
<<<<[<<<<<<<<<]>>>>>>>>>-]+[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<
<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-
<<<+>>>]<<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>
>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>>>
[-<<<->>>]<<<[->>>+<<<]>>>>>>>>]<<<<<<<<+<[>[->+>[-<-<<<<<<<<<<+>>>>>>>>>>>>[-<<
+>>]<]>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<<<]>>[-<+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>>]<]>
[-<<+>>]<<<<<<<<<<<<<]]>>>>[-<<<<+>>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>
>>>>>>]<<<<<<<<+<[>[->+>>[-<<-<<<<<<<<<<+>>>>>>>>>>>[-<+>]>]<[-<-<<<<<<<<<<+>>>>
>>>>>>>]<<]>>>[-<<+>[-<-<<<<<<<<<<+>>>>>>>>>>>]>]<[-<+>]<<<<<<<<<<<<]>>>>>+<<<<<
]>>>>>>>>>[>>>[-]>[-]>[-]>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>>>[-<<<<<
<+>>>>>>]<<<<<<[->>>>>>+<<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>+>[-<-<<<<+>>>>
>]>>[-<<<<<<<[->>>>>+<++<<<<]>>>>>[-<<<<<+>>>>>]<->+>>]<<[->>+<<]<<<<<[->>>>>+<<
<<<]+>>>>[-<<<<->>>>]+<<<<[->>>>->>>>>[>>>[-<<<->>>]+<<<[->>>-<[-<<+>>]<<[->>+<<
<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>[-<<->>]+<<[->>->[-<<<+>>>]<
<<[->>>+<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<
<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-<<<+>>>]<<<[->>>+>>>>>>[>+>[-<->]<[->+
<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>[->>>+<<<]>]<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>]<]>>[->>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>]>]<[->>>+<<<
]<<<<<<<<<<<]>>>>>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]]>>>>[-<<<<+>
>>>]<<<<[->>>>+>>>>>[>+>>[-<<->>]<<[->>+<<]>>>>>>>>]<<<<<<<<+<[>[->>>>+<<<[->>>-
<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[
->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<<<<<]]>>>>[-]<<<<]>>>>[-<<<<+>>
>>]<<<<[->>>>+>[-]>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+<<+<<<<<]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>[->>>>+<<<[->>>-<<<<<<<<<<<<<+>>>>>>>>>>>[->>+<<]<]>[->>-<<<<<<<<
<<<<<+>>>>>>>>>>>]<<]>[->>>+<<[->>-<<<<<<<<<<<<<+>>>>>>>>>>>]<]>[->>+<<]<<<<<<<<
<<<<]]>>>>>>>>>[>>[-]>[-]>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>[-]>[-]>>>>>[>>>>>[-<<<<+
>>>>]<<<<[->>>>+<<<+<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<+>>>>>
]<<<<<[->>>>>+<<<+<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>
>>>>>]+>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]>[-]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+[>+>>
>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>[-<<<<+>>>>]<<<<[->>>>+<<<<<[->>[-<<+
>>]<<[->>+>>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>
[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<]>[->>>>>>>>>+<<<<<<<<<]<+>>>>>>>>]<<<<<<<<<[>[-
]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+<<<<<<<<<]>>>>>>>>>
[>+>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>->>>>>[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<
<<[->>>[-<<<+>>>]<<<[->>>+>+<<<<]+>>>>>>>>>]<<<<<<<<[<<<<<<<<<]]>>>>>>>>>[>>>>>>
>>>]<<<<<<<<<[>>[->>>>>>>>>+<<<<<<<<<]<<<<<<<<<<<]>>[->>>>>>>>>+<<<<<<<<<]<<+>>>
>>>>>]<<<<<<<<<[>[-]<->>>>[-<<<<+>[<->-<<<<<<+>>>>>>]<[->+<]>>>>]<<<[->>>+<<<]<+
<<<<<<<<<]>>>>>>>>>[>>>>[-<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>]>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>+++++++++++++++[[>>>>>>>>
>]<<<<<<<<<-<<<<<<<<<[<<<<<<<<<]>>>>>>>>>-]+>>>>>>>>>>>>>>>>>>>>>+<<<[<<<<<<<<<]
>>>>>>>>>[>>>[-<<<->>>]+<<<[->>>->[-<<<<+>>>>]<<<<[->>>>+<<<<<<<<<<<<<[<<<<<<<<<
]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>[-<<<<->>>>]+<<<<[->>>>-<[-<<<+>>>]<<<[->>>+<
<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>
>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>->>[-<<<<+>>>>]<<<<[->>>>+<<[-]<<]>>]<<+>>>>[-<<<<
->>>>]+<<<<[->>>>-<<<<<<.>>]>>>>[-<<<<<<<.>>>>>>>]<<<[-]>[-]>[-]>[-]>[-]>[-]>>>[
>[-]>[-]>[-]>[-]>[-]>[-]>>>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-]>>>>]<<<<<<<<<
[<<<<<<<<<]>+++++++++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+>>>>>>>>>+<<<<<<<<
<<<<<<[<<<<<<<<<]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+[-]>>[>>>>>>>>>]<<<<<
<<<<[>>>>>>>[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<[<<<<<<<<<]>>>>>>>[-]+>>>]<<<<
<<<<<<]]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<[->>>>>>>+>>[>+>>>>[-<<<<->>>>]<<<<[->>>
>+<<<<]>>>>>>>>]<<+<<<<<<<[>>>>>[->>+<<]<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<
<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<<<<<[->>>>>>+<<<<<<]<
+<<<<<<<<<]>>>>>>>-<<<<[-]+<<<]+>>>>>>>[-<<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>->>[>>
>>>[->>+<<]>>>>]<<<<<<<<<[>[-]<->>>>>>>[-<<<<<<<+>[<->-<<<+>>>]<[->+<]>>>>>>>]<<
<<<<[->>>>>>+<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>+<<<
<<[<<<<<<<<<]>>>>>>>>>[>>>>>[-<<<<<->>>>>]+<<<<<[->>>>>->>[-<<<<<<<+>>>>>>>]<<<<
<<<[->>>>>>>+<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>[-<
<<<<<<->>>>>>>]+<<<<<<<[->>>>>>>-<<[-<<<<<+>>>>>]<<<<<[->>>>>+<<<<<<<<<<<<<<[<<<
<<<<<<]>>>[-]+>>>>>>[>>>>>>>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<
<<[<<<<<<<<<]>>>>[-]<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>-<<<<<[<<<<<<<
<<]]>>>]<<<<.>>>>>>>>>>[>>>>>>[-]>>>]<<<<<<<<<[<<<<<<<<<]>++++++++++[-[->>>>>>>>
>+<<<<<<<<<]>>>>>>>>>]>>>>>+>>>>>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-<<<<<<
<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+[-]>[>>>>>>>>>]<<<<<<<<<[>>>>>>>>[-<<<<<<<+>>>>>>
>]<<<<<<<[->>>>>>>+<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+>>]<<<<<<<<<<]]>>>>>>>>[-<<<<<
<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+>[>+>>>>>[-<<<<<->>>>>]<<<<<[->>>>>+<<<<<]>>>>>>
>>]<+<<<<<<<<[>>>>>>[->>+<<]<<<<<<<<<<<<<<<]>>>>>>>>>[>>>>>>>>>]<<<<<<<<<[>[-]<-
>>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<
<<<]>>>>>>>>-<<<<<[-]+<<<]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>->[>>>
>>>[->>+<<]>>>]<<<<<<<<<[>[-]<->>>>>>>>[-<<<<<<<<+>[<->-<<+>>]<[->+<]>>>>>>>>]<<
<<<<<[->>>>>>>+<<<<<<<]<+<<<<<<<<<]>+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>
+>>>>>>>>>>>>>>>>>>>>>>>>>>>+<<<<<<[<<<<<<<<<]>>>>>>>>>[>>>>>>[-<<<<<<->>>>>>]+<
<<<<<[->>>>>>->>[-<<<<<<<<+>>>>>>>>]<<<<<<<<[->>>>>>>>+<<<<<<<<<<<<<<<<<[<<<<<<<
<<]>>>>[-]+>>>>>[>>>>>>>>>]>+<]]+>>>>>>>>[-<<<<<<<<->>>>>>>>]+<<<<<<<<[->>>>>>>>
-<<[-<<<<<<+>>>>>>]<<<<<<[->>>>>>+<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+>>>>>>[>>>>>>
>>>]>[-]+<]]+>[-<[>>>>>>>>>]<<<<<<<<]>>>>>>>>]<<<<<<<<<[<<<<<<<<<]>>>>[-]<<<++++
+[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>->>>>>>>>>>>>>>>>>>>>>>>>>>>-<<<<<<[<<<<
<<<<<]]>>>]";
var paper=[];
var (ptr,pc)=(0,0);
var (code,inum,stack)=([],[],[]);
var (add,mov,jt,jf,in,out)=(0,1,2,3,4,5);
var color=[
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
"\e[90m","\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m"
];
var table=[];
func(){
var cnt=0;
for(var i=0;i<256;i+=1){
append(table,color[cnt]~chr(i)~"\e[0m");
cnt+=1;
if(cnt>12)
cnt=0;
}
}();
var funcs=[
func{paper[ptr]+=inum[pc];},
func{ptr+=inum[pc];},
func{if(paper[ptr])pc=inum[pc];},
func{if(!paper[ptr])pc=inum[pc];},
func{paper[ptr]=input()[0];},
func{print(table[paper[ptr]]);}
];
var bf=func(program){
setsize(paper,131072);
var len=size(program);
for(var i=0;i<len;i+=1){
var c=chr(program[i]);
if(c=='+' or c=='-'){
append(code,add);
append(inum,0);
for(;i<len;i+=1){
if(chr(program[i])=='+')
inum[-1]+=1;
elsif(chr(program[i])=='-')
inum[-1]-=1;
elsif(chr(program[i])!='\n'){
i-=1;
break;
}
}
}
elsif(c=='<' or c=='>'){
append(code,mov);
append(inum,0);
for(;i<len;i+=1){
if(chr(program[i])=='>')
inum[-1]+=1;
elsif(chr(program[i])=='<')
inum[-1]-=1;
elsif(chr(program[i])!='\n'){
i-=1;
break;
}
}
}
elsif(c==','){
append(code,in);
append(inum,0);
}
elsif(c=='.'){
append(code,out);
append(inum,0);
}
elsif(c=='['){
append(code,jf);
append(inum,0);
append(stack,size(code)-1);
}
elsif(c==']'){
if(!size(stack))
die("lack [");
var label=pop(stack);
append(code,jt);
append(inum,label-1);
inum[label]=size(code)-2;
}
}
if(size(stack)){
die("lack ]");
return;
}
len=size(code);
for(pc=0;pc<len;pc+=1)
funcs[code[pc]]();
return;
}
bf(mandelbrot);

View File

@@ -151,7 +151,7 @@ var bf=func(program)
{
var stack=[];
var len=size(program);
var f="import('lib.nas');\nvar ptr=0;\nvar paper=[];\nsetsize(paper,131072);\n";
var f="#automatically generated by bfconvertor.nas\nimport('lib.nas');\nvar ptr=0;\nvar paper=[];\nsetsize(paper,131072);\n";
for(var i=0;i<len;i+=1)
{
var c=chr(program[i]);
@@ -164,7 +164,7 @@ var bf=func(program)
cnt+=1;
elsif(chr(program[i])=='-')
cnt-=1;
else
elsif(chr(program[i])!='\n')
{
i-=1;
break;
@@ -187,7 +187,7 @@ var bf=func(program)
cnt+=1;
elsif(chr(program[i])=='<')
cnt-=1;
else
elsif(chr(program[i])!='\n')
{
i-=1;
break;

View File

@@ -1,27 +1,28 @@
import("stl/lib.nas");
import("stl/queue.nas");
rand(time(0));
var pixel=[' ','#','.','*'];
var map=[];
for(var i=0;i<10;i+=1)
{
append(map,[]);
for(var j=0;j<10;j+=1)
for(var j=0;j<20;j+=1)
append(map[i],(rand()>0.7));
}
var prt=func()
{
var s="";
var s="\e[0;0H+--------------------+\n";
for(var i=0;i<10;i+=1)
{
for(var j=0;j<10;j+=1)
s~=map[i][j];
s~='\n';
s~="|";
for(var j=0;j<20;j+=1)
s~=pixel[map[i][j]];
s~='|\n';
}
s~='----------\n';
s~='+--------------------+\n';
print(s);
unix.sleep(1/144);
}
var bfs=func(begin,end)
@@ -29,7 +30,8 @@ var bfs=func(begin,end)
var move=[[1,0],[0,1],[-1,0],[0,-1]];
var que=queue();
que.push(begin);
map[begin[0]][begin[1]]=3;
map[begin[0]][begin[1]]=2;
map[end[0]][end[1]]=0;
while(!que.empty())
{
var vertex=que.front();
@@ -40,13 +42,15 @@ var bfs=func(begin,end)
var y=vertex[1]+i[1];
if(x==end[0] and y==end[1])
{
map[x][y]='*';
map[x][y]=3;
prt();
print("reached.\n");
return;
}
if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0)
if(0<=x and x<10 and 0<=y and y<20 and map[x][y]==0)
{
que.push([x,y]);
map[x][y]=3;
map[x][y]=2;
}
}
prt();
@@ -55,4 +59,7 @@ var bfs=func(begin,end)
return;
}
bfs([0,0],[9,9]);
if(os.platform()=="windows")
system("chcp 65001");
print("\ec");
bfs([0,0],[9,19]);

View File

@@ -1 +1 @@
for(var i=0;i<4e6;i+=1);
for(var i=0;i<4e6;i+=1);

View File

@@ -1,5 +1,3 @@
import("lib.nas");
rand(time(0));
var new_neuron=func()

View File

@@ -1,32 +1,110 @@
import("lib.nas");
var filename=["main.cpp","nasal_ast.h","nasal_builtin.h","nasal_codegen.h","nasal_gc.h","nasal_import.h","nasal_lexer.h","nasal_parse.h","nasal_vm.h","nasal.h"];
var space=[" "," ","",""," "," "," "," "," "," "];
var enter_cnt=func(s)
{
var (cnt,len,enter)=(0,size(s),'\n'[0]);
var source=[
"main.cpp ",
"nasal_err.h ",
"nasal_ast.h ",
"nasal_builtin.h ",
"nasal_codegen.h ",
"nasal_opt.h ",
"nasal_gc.h ",
"nasal_import.h ",
"nasal_lexer.h ",
"nasal_parse.h ",
"nasal_vm.h ",
"nasal_dbg.h ",
"nasal.h "
];
var lib=[
"stl/file.nas ",
"stl/lib.nas ",
"stl/list.nas ",
"stl/module.nas ",
"stl/queue.nas ",
"stl/result.nas ",
"stl/sort.nas ",
"stl/stack.nas "
];
var testfile=[
"test/ascii-art.nas ",
"test/auto_crash.nas ",
"test/bf.nas ",
"test/bfcolored.nas ",
"test/bfconvertor.nas ",
"test/bfs.nas ",
"test/bigloop.nas ",
"test/bp.nas ",
"test/calc.nas ",
"test/choice.nas ",
"test/class.nas ",
"test/diff.nas ",
"test/exception.nas ",
"test/fib.nas ",
"test/filesystem.nas ",
"test/hexdump.nas ",
"test/json.nas ",
"test/leetcode1319.nas ",
"test/lexer.nas ",
"test/life.nas ",
"test/loop.nas ",
"test/mandel.nas ",
"test/mandelbrot.nas ",
"test/md5.nas ",
"test/md5compare.nas ",
"test/module_test.nas ",
"test/nasal_test.nas ",
"test/pi.nas ",
"test/prime.nas ",
"test/props_sim.nas ",
"test/props.nas ",
"test/qrcode.nas ",
"test/quick_sort.nas ",
"test/scalar.nas ",
"test/snake.nas ",
"test/tetris.nas ",
"test/trait.nas ",
"test/turingmachine.nas",
"test/utf8chk.nas ",
"test/wavecollapse.nas ",
"test/ycombinator.nas "
];
var module=[
"module/fib.cpp ",
"module/keyboard.cpp ",
"module/libfib.nas ",
"module/libkey.nas "
];
var getname=func(s){
var (len,ch)=(size(s),' '[0]);
for(var i=0;i<len and s[i]!=ch;i+=1);
return substr(s,0,i);
}
var count=func(s,c){
var (cnt,len,ch)=(0,size(s),c[0]);
for(var i=0;i<len;i+=1)
cnt+=(s[i]==enter);
cnt+=(s[i]==ch);
return cnt;
}
var semic_cnt=func(s)
{
var (cnt,len,semi)=(0,size(s),';'[0]);
for(var i=0;i<len;i+=1)
cnt+=(s[i]==semi);
return cnt;
}
func(){
var (bytes,line,semi)=(0,0,0);
forindex(var i;filename)
{
var s=io.fin(filename[i]);
var calc=func(codetype,files){
println(codetype);
var (bytes,line,semi,line_cnt,semi_cnt)=(0,0,0,0,0);
forindex(var i;files){
var s=io.fin(getname(files[i]));
(line_cnt,semi_cnt)=(count(s,'\n'),count(s,';'));
println(files[i],'| ',line_cnt,' \tline | ',semi_cnt,' \tsemi');
bytes+=size(s);
var line_cnt=enter_cnt(s);
var semi_cnt=semic_cnt(s);
println(filename[i],space[i],'| ',line_cnt,' \tline | ',semi_cnt,' \tsemi');
line+=line_cnt;
semi+=semi_cnt;
}
println('total: | ',line,' \tline | ',semi,' \tsemi');
println('bytes: | ',bytes,' bytes| ',int(bytes/1024),' \tkb');
}();
println('total: | ',line,' \tline | ',semi,' \tsemi');
println(' | ',bytes,'\tbytes| ',int(bytes/1024),' \tkb');
}
calc("source code:",source);
calc("lib:",lib);
calc("test file:",testfile);
calc("module:",module);

View File

@@ -1,4 +1,3 @@
import("lib.nas");
var condition_true=1;
var condition_false=0;
if(condition_true)

View File

@@ -1,17 +1,10 @@
import("lib.nas");
var student=func(name,age)
{
var val={
name:name,
age:age
};
var student=func(n,a){
return {
print_info:func(){println(val.name,' ',val.age);},
set_age: func(age){val.age=age;},
get_age: func(){return val.age;},
set_name: func(name){val.name=name;},
get_name: func(){return val.name;}
print_info:func println(n,' ',a),
set_age: func(age) a=age,
get_age: func return a,
set_name: func(name) n=name,
get_name: func return n
};
}
var s=student('valk',24);
@@ -24,4 +17,46 @@ println(s.get_age(),' ',s.get_name());
s.set_age(20);
s.set_name('Sidi Liang');
s.print_info();
println(s.get_age(),' ',s.get_name());
println(s.get_age(),' ',s.get_name());
# flightgear nasal-console cannot use this kind of object initializing
var m=func(){
var (_1,_2)=(0,1);
return {
a:func(){
print(_1,' ',_2,'\n');
},
b:func(x){
_1=x;
},
c:func(x){
_2=x;
},
d:func(x){
return func{
print(_1,' ',_2,' ',x,'\n');
};
},
g:func(x){
var y=x;
return func{
print(_1,' ',_2,' ',x,' ',y,'\n');
}
},
h:func(){
return func(x){
_1=x;
}
}
};
}();
m.a(); # 0 1
m.b(2048);
m.c(1024);
var a=m.d(-1);
var b=m.g(1);
a(); # 2048 1024 -1
b(); # 2048 1024 1 1
m.h()(2147483647);
m.a();# 2147483647 1024

129
test/diff.nas Normal file
View File

@@ -0,0 +1,129 @@
var myers=func(src,dst,show_table=0){
(src,dst)=(split("\n",src),split("\n",dst));
append(src,"");
append(dst,"");
var (src_len,dst_len)=(size(src),size(dst));
var mat=[];
setsize(mat,dst_len*src_len);
forindex(var i;mat){
mat[i]=0;
}
var visited=[];
setsize(visited,dst_len*src_len);
forindex(var i;visited){
visited[i]=0;
}
forindex(var y;dst)
forindex(var x;src)
mat[y*src_len+x]=(src[x]==dst[y]);
if(show_table){
var curve=[
["+---",
"| "],
[
"+---",
"| \\ "]
];
var s="";
forindex(var y;dst){
forindex(var t;curve[0]){
forindex(var x;src){
s~=curve[mat[y*src_len+x]][t];
}
s~=["+","|"][t]~"\n";
}
}
forindex(var i;src)
s~="+---";
print(s~"+\n");
}
var total=[];
var path=[];
var vec=[[0,0,-1]];
visited[0]=1;
while(size(vec)){
append(total,vec);
var tmp=[];
forindex(var i;vec){
var elem=vec[i];
var (x,y)=(elem[1],elem[0]);
# find solution
if(x==src_len-1 and y==dst_len-1){
append(path,vec[i]);
for(var (prev,iter)=(elem[2],size(total)-1);iter>0;iter-=1){
var t=total[iter-1][prev];
append(path,t);
prev=t[2];
}
if(show_table){
for(var t=size(path)-1;t>=0;t-=1)
print("("~path[t][1]~","~path[t][0]~")",t==0?"":"->");
println();
}
# reverse path
for(var t=0;t<size(path)/2;t+=1)
(path[t],path[-1-t])=(path[-1-t],path[t]);
# print diff
for(var t=1;t<size(path);t+=1){
var (prev_x,prev_y)=(path[t-1][1],path[t-1][0]);
var (x,y)=(path[t][1],path[t][0]);
var (sub_x,sub_y)=(x-prev_x,y-prev_y);
if(sub_x==1 and sub_y==1){
if(show_table)
println(" ",src[prev_x]);
}elsif(sub_x==1 and sub_y==0){
println("\e[31m - ",src[prev_x],"\e[0m");
}elsif(sub_x==0 and sub_y==1){
println("\e[32m + ",dst[prev_y],"\e[0m");
}
}
return;
}
# do bfs
if(mat[y*src_len+x]==1){
if(x+1<src_len and y+1<dst_len and visited[(y+1)*src_len+x+1]==0){
append(tmp,[y+1,x+1,i]);
visited[(y+1)*src_len+x+1]=1;
}
}
else{
if(x+1<src_len and visited[y*src_len+x+1]==0){
append(tmp,[y,x+1,i]);
visited[y*src_len+x+1]=1;
}
if(y+1<dst_len and visited[(y+1)*src_len+x]==0){
append(tmp,[y+1,x,i]);
visited[(y+1)*src_len+x]=1;
}
}
}
vec=tmp;
}
}
func(diff){
diff(
"var a=0;\nvar b=1;\nprint(\"hello \",a);\nvar c=2;\nc=[];\nvar d=3;\nvar l=list();\nvar q=queue();\n",
"var a=0;\nvar b=1;\nb=[];\nprintln(\"hello \",a);\nvar c=2;\nvar d=3;\nprintln(\"hello world!\");\nvar l=list();\nvar q=queue();\n",
1
);
print("\n");
diff(
"A\nB\nC\nA\nB\nB\nA\n",
"C\nB\nA\nB\nA\nC\n",
1
);
print("\n");
diff(
io.fin("test/bf.nas"),
io.fin("test/bfcolored.nas")
);
}(myers);

37
test/exception.nas Normal file
View File

@@ -0,0 +1,37 @@
var ResultTrait={
Ok:func(val){
me.ok=val;
me.flag=0;
return me;
},
Err:func(info){
me.err=info;
me.flag=1;
return me;
},
unwrap:func(){
if(me.flag)
die(me.err);
return me.ok;
}
};
var Result=func(){
return{
ok:nil,
err:"",
flag:1,
parents:[ResultTrait]
};
};
var a=func(){
return Result().Ok("hello world");
}
var b=func(){
return Result().Err("exception test");
}
println(a().unwrap());
b().unwrap();

View File

@@ -1,4 +1,3 @@
import("lib.nas");
var fib=func(x)
{
if(x<2) return x;

34
test/filesystem.nas Normal file
View File

@@ -0,0 +1,34 @@
var fd=io.open("test/filesystem.nas");
while((var line=io.readln(fd))!=nil)
println(line);
io.close(fd);
println(io.stat("test/filesystem.nas"));
var dd=unix.opendir("test");
while(var name=unix.readdir(dd))
println(name);
unix.closedir(dd);
var files=func(dir){
var dd=unix.opendir(dir);
var res=[];
while(var n=unix.readdir(dd))
append(res,n);
unix.closedir(dd);
return res;
}
var prt=func(s,path){
foreach(var i;files(path)){
print(s,i);
if(unix.isdir(path~'/'~i)){
print(' <dir>\n');
if(i!='.' and i!='..')
prt(s~' |',path~'/'~i);
}
elsif(unix.isfile(path~'/'~i))
print(" <file>\n");
else
print(' <unknown>\n');
}
}
prt('',".");

84
test/hexdump.nas Normal file
View File

@@ -0,0 +1,84 @@
# hexdump.nas by ValKmjolnir
# 2021/8/13
# init
var hex_num=[
'0','1','2','3',
'4','5','6','7',
'8','9','a','b',
'c','d','e','f'
];
var hex=[];
foreach(var i;hex_num)
foreach(var j;hex_num)
append(hex,i~j);
# read file
var s=func(){
var filename=[
"nasal.h",
"main.cpp",
"nasal_ast.h",
"nasal_builtin.h",
"nasal_codegen.h",
"nasal_gc.h",
"nasal_import.h",
"nasal_lexer.h",
"nasal_parse.h",
"nasal_vm.h",
];
var ret="";
foreach(var elem;filename)
ret~=io.fin(elem);
return ret;
}();
# used to change line and control the spaces
var cnt=0;
# used to print hex index
var hex_index=[0,0,0,0];
# print binary in text format
var textprint=func(index){
var info='';
for(var i=index-cnt;i<index;i+=1)
info~=(0<=s[i] and s[i]<32)?'.':chr(s[i]);
for(var i=cnt;i<16;i+=1)
info~='.';
return ' |'~info~'|\n';
}
# print index
var indexprint=func(index){
forindex(var i;hex_index){
hex_index[i]=index-int(index/256)*256;
index=int(index/256);
}
var info='';
for(var i=3;i>=0;i-=1)
info~=hex[hex_index[i]];
return info~' ';
}
# main
func(){
var info=indexprint(0);
for(var i=0;i<size(s);i+=1){
if(cnt==16){
info~=textprint(i);
print(info);
cnt=0;
info=indexprint(i);
}elsif(cnt==8)
info~=' ';
cnt+=1;
info~=hex[s[i]]~' ';
}
for(var l=cnt;l<16;l+=1)
info~=' ';
if(cnt<=8)
info~=' ';
info~=textprint(i);
print(info);
}();

View File

@@ -1,196 +1,322 @@
#lib json.nas
import("lib.nas");
var json={
text:'',
line:1,
size:0,
ptr:0,
get:nil,
check:nil,
next:nil,
match:nil,
hash_gen:nil,
vec_gen:nil,
member:nil,
parse:nil,
token:{content:'',type:''},
content:[],
};
var JSON=func(){
json.get=func(filename)
{
me.line=1;
me.ptr=0;
me.content=[];
me.token={content:'',type:''};
me.text=io.fin(filename);
if(!size(me.text))
die("cannot open "~filename);
me.text=split('',me.text);
me.size=size(me.text);
return;
}
var (
j_eof,
j_lbrace,
j_rbrace,
j_lbracket,
j_rbracket,
j_comma,
j_colon,
j_str,
j_num,
j_id
)=(
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
);
var j_content=[
"eof",
"`{`",
"`}`",
"`[`",
"`]`",
"`,`",
"`:`",
"string",
"number",
"identifier"
];
json.check=func(ptr)
{
var str=me.text[ptr];
return (str=='{' or str=='}' or str=='[' or str==']' or str==',' or str==':' or str=='\"' or ('0'<=str and str<='9'));
}
json.next=func()
{
while(me.ptr<me.size and !json.check(me.ptr))
{
if(me.text[me.ptr]=='\n')
me.line+=1;
me.ptr+=1;
var text='';
var line=1;
var text_size=0;
var ptr=0;
var token={content:'',type:''};
var content={};
var init=func(){
line=1;
text_size=0;
ptr=0;
content={};
token={content:'',type:''};
text='';
}
if(me.ptr>=me.size)
var isnum=func(c){
return '0'<=c and c<='9';
}
var isid=func(c){
var tmp=c[0];
return ('a'[0]<=tmp and tmp<='z'[0]) or
('A'[0]<=tmp and tmp<='Z'[0]) or
c=='_';
}
var check=func()
{
me.token.content="";
me.token.type="eof";
var c=text[ptr];
return (
c=='{' or c=='}' or
c=='[' or c==']' or
c==',' or c==':' or
c=='\"' or c=='\'' or
isnum(c) or isid(c)
);
}
var get=func(str)
{
init();
if(!size(str))
die("empty string");
text=split('',str);
text_size=size(text);
return;
}
if(me.text[me.ptr]=='{')
var next=func()
{
me.token.content='{';
me.token.type="left brace";
}
elsif(me.text[me.ptr]=='}')
{
me.token.content='}';
me.token.type="right brace";
}
elsif(me.text[me.ptr]=='[')
{
me.token.content='[';
me.token.type="left bracket";
}
elsif(me.text[me.ptr]==']')
{
me.token.content=']';
me.token.type="right bracket";
}
elsif(me.text[me.ptr]==',')
{
me.token.content=',';
me.token.type="comma";
}
elsif(me.text[me.ptr]==':')
{
me.token.content=':';
me.token.type="colon";
}
elsif(me.text[me.ptr]=='\"')
{
var s="";
me.ptr+=1;
while(me.ptr<me.size and me.text[me.ptr]!='\"')
while(ptr<text_size and !check())
{
s~=me.text[me.ptr];
me.ptr+=1;
if(text[ptr]=='\n')
line+=1;
ptr+=1;
}
me.token.content=s;
me.token.type="string";
}
elsif('0'<=me.text[me.ptr] and me.text[me.ptr]<='9')
{
var s=me.text[me.ptr];
me.ptr+=1;
while(me.ptr<me.size and (('0'<=me.text[me.ptr] and me.text[me.ptr]<='9') or me.text[me.ptr]=='.'))
if(ptr>=text_size)
{
s~=me.text[me.ptr];
me.ptr+=1;
token.content="eof";
token.type=j_eof;
return;
}
me.ptr-=1;
me.token.content=num(s);
me.token.type="number";
}
me.ptr+=1;
return;
}
json.match=func(type)
{
if(me.token.type!=type)
print("line ",me.line,": expect ",type," but get ",me.token.content,".");
me.next();
return;
}
json.hash_gen=func()
{
var hash={};
me.match("left brace");
me.member(hash);
while(me.token.type=="comma")
{
me.match("comma");
me.member(hash);
}
me.match("right brace");
return hash;
}
json.vec_gen=func()
{
var vec=[];
me.match("left bracket");
if(me.token.type=="left brace")
append(vec,me.hash_gen());
elsif(me.token.type=="left bracket")
append(vec,me.vec_gen());
elsif(me.token.type=="string" or me.token.type=="number")
{
append(vec,me.token.content);
me.next();
}
while(me.token.type=="comma")
{
me.match("comma");
if(me.token.type=="left brace")
append(vec,me.hash_gen());
elsif(me.token.type=="left bracket")
append(vec,me.vec_gen());
elsif(me.token.type=="string" or me.token.type=="number")
var c=text[ptr];
if(c=='{')
{
append(vec,me.token.content);
me.next();
token.content='{';
token.type=j_lbrace;
}
elsif(c=='}')
{
token.content='}';
token.type=j_rbrace;
}
elsif(c=='[')
{
token.content='[';
token.type=j_lbracket;
}
elsif(c==']')
{
token.content=']';
token.type=j_rbracket;
}
elsif(c==',')
{
token.content=',';
token.type=j_comma;
}
elsif(c==':')
{
token.content=':';
token.type=j_colon;
}
elsif(c=='\"' or c=='\'')
{
var strbegin=c;
var s="";
ptr+=1;
while(ptr<text_size and text[ptr]!=strbegin)
{
s~=text[ptr];
ptr+=1;
}
token.content=s;
token.type=j_str;
}
elsif(isnum(c))
{
var s=c;
ptr+=1;
while(ptr<text_size and ((isnum(text[ptr]) or text[ptr]=='.')))
{
s~=text[ptr];
ptr+=1;
}
ptr-=1;
token.content=num(s);
token.type=j_num;
}
elsif(isid(c))
{
var s=c;
ptr+=1;
while(ptr<text_size and (isid(text[ptr]) or isnum(text[ptr])))
{
s~=text[ptr];
ptr+=1;
}
ptr-=1;
token.content=s;
token.type=j_id;
}
ptr+=1;
return;
}
me.match("right bracket");
return vec;
}
json.member=func(hash)
{
var name=me.token.content;
me.match("string");
me.match("colon");
if(me.token.type=="left brace")
hash[name]=me.hash_gen();
elsif(me.token.type=="left bracket")
hash[name]=me.vec_gen();
elsif(me.token.type=="string" or me.token.type=="number")
var match=func(type)
{
hash[name]=me.token.content;
me.next();
if(token.type!=type)
print("line ",line,": expect ",j_content[type]," but get `",token.content,"`.\n");
next();
return;
}
return;
}
json.parse=func()
{
me.content={};
me.next();
me.match("left brace");
me.member(me.content);
while(me.token.type=="comma")
var hash_gen=func()
{
me.match("comma");
me.member(me.content);
var hash={};
match(j_lbrace);
member(hash);
while(token.type==j_comma)
{
match(j_comma);
member(hash);
}
match(j_rbrace);
return hash;
}
me.match("right brace");
return;
}
var vec_gen=func()
{
var vec=[];
match(j_lbracket);
if(token.type==j_lbrace)
append(vec,hash_gen());
elsif(token.type==j_lbracket)
append(vec,vec_gen());
elsif(token.type==j_str or token.type==j_num)
{
append(vec,token.content);
next();
}
while(token.type==j_comma)
{
match(j_comma);
if(token.type==j_lbrace)
append(vec,me.hash_gen());
elsif(token.type==j_lbracket)
append(vec,vec_gen());
elsif(token.type==j_str or token.type==j_num)
{
append(vec,token.content);
next();
}
}
match(j_rbracket);
return vec;
}
var member=func(hash)
{
var name=token.content;
if(token.type==j_str)
match(j_str);
else
match(j_id);
match(j_colon);
if(token.type==j_lbrace)
hash[name]=hash_gen();
elsif(token.type==j_lbracket)
hash[name]=vec_gen();
elsif(token.type==j_str or token.type==j_num)
{
hash[name]=token.content;
next();
}
return;
}
return {
parse:func(str)
{
if(typeof(str)!="str")
die("JSON.parse: must use string");
get(str);
next();
match(j_lbrace);
member(content);
while(token.type==j_comma)
{
match(j_comma);
member(content);
}
match(j_rbrace);
var res=content;
init();
return res;
},
stringify:func(hash){
if(typeof(hash)!="hash")
die("JSON.stringify: must use hashmap");
var s="";
var gen=func(elem){
var t=typeof(elem);
if(t=="num")
s~=elem;
elsif(t=="str")
s~='"'~elem~'"';
elsif(t=="vec")
vgen(elem);
elsif(t=="hash")
hgen(elem);
else
s~='"undefined"';
}
var vgen=func(v){
s~="[";
var vsize=size(v);
for(var i=0;i<vsize;i+=1){
gen(v[i]);
if(i!=vsize-1)
s~=",";
}
s~="]";
}
var hgen=func(h){
s~="{";
var k=keys(h);
var vsize=size(k);
for(var i=0;i<vsize;i+=1){
s~=k[i]~":";
gen(h[k[i]]);
if(i!=vsize-1)
s~=",";
}
s~="}";
}
hgen(hash);
return s;
}
};
}();
var ss=JSON.stringify({
vec:[0,1,2],
hash:{
m1:0,
m2:"str",
m3:[114514],
m4:{year:1919,month:8,date:10}
},
function:func(){}
});
println(ss);
println(JSON.parse(ss));

View File

@@ -1,4 +1,3 @@
import("lib.nas");
# union set
var n=4;
var input=[[0,1],[0,2],[1,2]];

View File

@@ -1,23 +1,32 @@
import("lib.nas");
var lexer=func(file)
{
var _={s:io.fin(file),len:0,ptr:0,token:[]};
_.len=size(_.s);
var (ptr,token)=(0,[]);
var s=io.fin(file);
var len=size(s);
var line=0;
var gen=func(tok)
{
append(token,{
line:line,
token:tok
});
}
return
{
jmp_note:func()
{
while(_.ptr<_.len and chr(_.s[_.ptr])!='\n')
_.ptr+=1;
_.ptr+=1;
while(ptr<len and s[ptr]!='\n'[0])
ptr+=1;
if(ptr<len and s[ptr]=='\n'[0])
line+=1;
ptr+=1;
},
id_gen:func()
{
var tmp="";
while(_.ptr<_.len)
while(ptr<len)
{
var c=_.s[_.ptr];
var c=s[ptr];
if(('a'[0]<=c and c<='z'[0])
or ('A'[0]<=c and c<='Z'[0])
or ('0'[0]<=c and c<='9'[0])
@@ -25,29 +34,30 @@ var lexer=func(file)
tmp~=chr(c);
else
break;
_.ptr+=1;
ptr+=1;
}
append(_.token,tmp);
gen(tmp);
},
str_gen:func()
{
var str="";
var mark=chr(_.s[_.ptr]);
_.ptr+=1;
while(_.ptr<_.len and chr(_.s[_.ptr])!=mark)
var mark=chr(s[ptr]);
ptr+=1;
while(ptr<len and chr(s[ptr])!=mark)
{
if(chr(_.s[_.ptr])=='\\')
if(chr(s[ptr])=='\\')
{
_.ptr+=1;
var c=chr(_.s[_.ptr]);
ptr+=1;
var c=chr(s[ptr]);
if (c=='a' ) str~='\a';
elsif(c=='b' ) str~='\b';
elsif(c=='e' ) str~='\e';
elsif(c=='f' ) str~='\f';
elsif(c=='n' ) str~='\n';
elsif(c=='r' ) str~='\r';
elsif(c=='t' ) str~='\t';
elsif(c=='v' ) str~='\v';
elsif(c=='?' ) str~='?';
elsif(c=='?' ) str~='\?';
elsif(c=='0' ) str~='\0';
elsif(c=='\\') str~='\\';
elsif(c=='\'') str~='\'';
@@ -55,118 +65,128 @@ var lexer=func(file)
else str~=c;
}
else
str~=chr(_.s[_.ptr]);
_.ptr+=1;
{
if(s[ptr]=='\n'[0])
line+=1;
str~=chr(s[ptr]);
}
ptr+=1;
}
if(_.ptr>=_.len)
if(ptr>=len)
print("read eof when generating string.\n");
_.ptr+=1;
append(_.token,str);
ptr+=1;
gen(str);
},
num_gen:func()
{
var number=chr(_.s[_.ptr]);
_.ptr+=1;
if(_.ptr<_.len and chr(_.s[_.ptr])=='x')
var number=chr(s[ptr]);
ptr+=1;
if(ptr<len and chr(s[ptr])=='x')
{
_.ptr+=1;
while(_.ptr<_.len and
('a'[0]<=_.s[_.ptr] and _.s[_.ptr]<='f'[0]
or '0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
ptr+=1;
while(ptr<len and
('a'[0]<=s[ptr] and s[ptr]<='f'[0]
or '0'[0]<=s[ptr] and s[ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
number~=chr(s[ptr]);
ptr+=1;
}
append(_.token,num(number));
gen(num(number));
return;
}
elsif(_.ptr<_.len and chr(_.s[_.ptr])=='o')
elsif(ptr<len and chr(s[ptr])=='o')
{
_.ptr+=1;
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='7'[0]))
ptr+=1;
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='7'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
number~=chr(s[ptr]);
ptr+=1;
}
append(_.token,num(number));
gen(num(number));
return;
}
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
number~=chr(s[ptr]);
ptr+=1;
}
if(_.ptr<_.len and chr(_.s[_.ptr])=='.')
if(ptr<len and chr(s[ptr])=='.')
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
number~=chr(s[ptr]);
ptr+=1;
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
number~=chr(s[ptr]);
ptr+=1;
}
}
if(chr(_.s[_.ptr])=='e' or chr(_.s[_.ptr])=='E')
if(chr(s[ptr])=='e' or chr(s[ptr])=='E')
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
if(chr(_.s[_.ptr])=='-' or chr(_.s[_.ptr])=='+')
number~=chr(s[ptr]);
ptr+=1;
if(chr(s[ptr])=='-' or chr(s[ptr])=='+')
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
number~=chr(s[ptr]);
ptr+=1;
}
while(_.ptr<_.len and ('0'[0]<=_.s[_.ptr] and _.s[_.ptr]<='9'[0]))
while(ptr<len and ('0'[0]<=s[ptr] and s[ptr]<='9'[0]))
{
number~=chr(_.s[_.ptr]);
_.ptr+=1;
number~=chr(s[ptr]);
ptr+=1;
}
}
var last_c=chr(number[-1]);
if(last_c=='.' or last_c=='e' or last_c=='E' or last_c=='-' or last_c=='+')
println("error number: ",number);
append(_.token,num(number));
gen(num(number));
},
opr_gen:func()
{
var c=chr(_.s[_.ptr]);
var c=chr(s[ptr]);
if(c=='+' or c=='-' or c=='~' or c=='/' or c=='*' or c=='>' or c=='<' or c=='!' or c=='=')
{
var tmp=c;
_.ptr+=1;
if(_.ptr<_.len and chr(_.s[_.ptr])=='=')
ptr+=1;
if(ptr<len and chr(s[ptr])=='=')
{
tmp~=chr(_.s[_.ptr]);
_.ptr+=1;
tmp~=chr(s[ptr]);
ptr+=1;
}
append(_.token,tmp);
gen(tmp);
return;
}
elsif(c=='.')
{
if(_.ptr+2<_.len and chr(_.s[_.ptr+1])=='.' and chr(_.s[_.ptr+2])=='.')
if(ptr+2<len and chr(s[ptr+1])=='.' and chr(s[ptr+2])=='.')
{
append(_.token,"...");
_.ptr+=3;
gen("...");
ptr+=3;
}
else
{
append(_.token,".");
_.ptr+=1;
gen(".");
ptr+=1;
}
return;
}
elsif(c!=' ' and c!='\t' and c!='\n' and c!='\r' and _.s[_.ptr]>0)
append(_.token,c);
_.ptr+=1;
elsif(c!=' ' and c!='\t' and c!='\n' and c!='\r' and s[ptr]>0)
gen(c);
ptr+=1;
return;
},
main:func()
compile:func()
{
while(_.ptr<_.len)
line=1;
while(ptr<len)
{
var c=_.s[_.ptr];
var c=s[ptr];
if(c=='#'[0])
me.jmp_note();
elsif(c=='\n'[0])
{
line+=1;
ptr+=1;
}
elsif('a'[0]<=c and c<='z'[0]
or 'A'[0]<=c and c<='Z'[0]
or c=='_'[0])
@@ -180,12 +200,11 @@ var lexer=func(file)
}
return;
},
get_token:func(){return _.token;}
get_token:func(){return token;}
};
}
var nasal_lexer=lexer("test/lexer.nas");
nasal_lexer.main();
foreach(var tok;nasal_lexer.get_token())
print(tok,' ');
println();
var lex=lexer("test/props.nas");
lex.compile();
foreach(var tok;lex.get_token())
print('(',tok.line,' | ',tok.token,')\n');

View File

@@ -1,5 +1,3 @@
import("lib.nas");
var map=nil;
var check=func(x,y)
@@ -23,19 +21,22 @@ var new_map=func()
var prt=func()
{
var s='';
var s='\e[0;0H';
foreach(var line;map)
{
foreach(var elem;line)
s~=elem~' ';
s~='\n';
}
system("cls");
print(s);
unix.sleep(1/144);
}
func()
{
if(os.platform()=="windows")
system("chcp 65001");
print("\ec");
rand(time(0));
map=new_map();
forindex(var i;map)

View File

@@ -1,4 +1,3 @@
import("lib.nas");
for(;;)break;
for(;;)
{
@@ -7,25 +6,32 @@ for(;;)
}
for(var i=1;;)break;
for(var i=1;;i+=1)break;
for(var i=1;i<10;i+=1)print(i);
for(var i=1;i<10;i+=1)print(i,'\n');
while(1)break;
var j=0;
while(j<10)
{
print(j);
print(j,'\n');
j+=1;
}
forindex(var j;[0,1,2,3])print(j);
forindex(var j;[0,1,2,3])print(j,'\n');
forindex(var j;[0,1,2,3])
{
var a=j;
print(a*a);
print(a*a,'\n');
}
foreach(var j;[0,1,2,3])print([0,1,2,3][j]);
foreach(var j;[0,1,2,3])print([0,1,2,3][j],'\n');
foreach(var j;[0,1,2,3])
{
var a=[0,1,2,3][j];
print(a*a-1);
print(a*a-1,'\n');
}
var f=func(){
var x=0;
return func(){x+=1;};
}();
for(var i=0;i<4e6;i+=1)
f();

4808
test/mandel.nas Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
import("lib.nas");
var (yMin,yMax,xMin,xMax,line)=(-0.2,0.2,-1.5,-1.0,"");
var (yDel,xDel)=(yMax-yMin,xMax-xMin);
for(var yPixel=0;yPixel<24;yPixel+=1)

247
test/md5.nas Normal file
View File

@@ -0,0 +1,247 @@
var check=func(x){
if(x<0x100000000)
return x;
return x-floor(x/0x100000000)*0x100000000;
}
var u32_bits_and=func(x,y){
(x,y)=(check(x),check(y));
var (res,op)=(0,1);
for(var i=0;i<32;i+=1){
var (tmpx,tmpy)=(x-floor(x/2)*2,y-floor(y/2)*2);
res+=op*(tmpx==1 and tmpy==1);
(x,y)=(floor(x/2),floor(y/2));
op*=2;
}
return res;
}
var u32_bits_or=func(x,y){
(x,y)=(check(x),check(y));
var (res,op)=(0,1);
for(var i=0;i<32;i+=1){
var (tmpx,tmpy)=(x-floor(x/2)*2,y-floor(y/2)*2);
res+=op*(tmpx==1 or tmpy==1);
(x,y)=(floor(x/2),floor(y/2));
op*=2;
}
return res;
}
var u32_bits_xor=func(x,y){
(x,y)=(check(x),check(y));
var (res,op)=(0,1);
for(var i=0;i<32;i+=1){
var (tmpx,tmpy)=(x-floor(x/2)*2,y-floor(y/2)*2);
res+=op*(tmpx!=tmpy);
(x,y)=(floor(x/2),floor(y/2));
op*=2;
}
return res;
}
var u32_bits_not=func(x){
x=check(x);
var (res,op)=(0,1);
for(var i=0;i<32;i+=1){
res+=op*((x-floor(x/2)*2)==1?0:1);
x=floor(x/2);
op*=2;
}
return res;
}
var hex32str=func(){
var ch=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];
var tbl=[];
setsize(tbl,256);
for(var i=0;i<16;i+=1){
for(var j=0;j<16;j+=1)
tbl[i*16+j]=ch[i]~ch[j];
}
return func(num){
var res="";
for(var i=0;i<4;i+=1){
res~=tbl[u32_bits_and(num,0xff)];
num=floor(num/256);
}
return res;
};
}();
var _md5=func(){
var K=[
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
];
var S=[
7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
];
var idx=[
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
];
var l=func(num,cx){
for(var i=0;i<cx;i+=1){
num=check(num*2);
}
return num;
}
var r=func(num,cx){
num=check(num);
for(var i=0;i<cx;i+=1){
num=num/2;
}
return floor(num);
}
var rol=func(num,cx){
return u32_bits_or(l(num,cx),r(num,32-cx));
}
# round 1
var F=func(x,y,z){
return u32_bits_or(
u32_bits_and(x,y),
u32_bits_and(u32_bits_not(x),z)
);
}
# round 2
var G=func(x,y,z){
return u32_bits_or(
u32_bits_and(x,z),
u32_bits_and(y,u32_bits_not(z))
);
}
# round 3
var H=func(x,y,z){
return u32_bits_xor(u32_bits_xor(x,y),z);
}
# round 4
var I=func(x,y,z){
return u32_bits_xor(
y,
u32_bits_or(x,u32_bits_not(z))
);
}
var functions=[
F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,
G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,G,
H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I
];
return func(s){
var (s_size,len,res)=(size(s),size(s)*8,[]);
setsize(res,s_size);
for(var i=0;i<s_size;i+=1){
res[i]=s[i];
}
# +------len------+--1~512--+--64--+
# | text | fill | size |
# +---------------+---------+------+ N*512 bit
var (mod,res_size)=(s_size-floor(s_size/64)*64,0);
if(mod==56){
res_size=s_size+64;
}elsif(mod<56){
res_size=floor(s_size/64)*64+56;
}elsif(mod>56){
res_size=floor(s_size/64)*64+120; # 512+448=960 960/8=120
}
setsize(res,res_size);
res[s_size]=0x80;
for(var i=s_size+1;i<res_size;i+=1)
res[i]=0;
# little endian
setsize(res,size(res)+8);
var (s_size,lower32,higher32)=(size(res),check(len),check(len/math.pow(2,32)));
for(var i=4;i>0;i-=1){
res[s_size-4-i]=floor(lower32-floor(lower32/256)*256);
lower32=floor(lower32/256);
}
for(var i=4;i>0;i-=1){
res[s_size-i]=floor(higher32-floor(higher32/256)*256);
higher32=floor(higher32/256);
}
# 1 block=>16 uint32=>64 byte=>512 bit
# because using double to discribe number
# this may only work when string's length is under 1<<51
var tmp=[];
setsize(tmp,size(res)/4);
for(var i=0;i<size(res);i+=4){
tmp[i/4]=res[i+3]*math.pow(2,24)+
res[i+2]*math.pow(2,16)+
res[i+1]*math.pow(2,8)+
res[i];
}
res=tmp;
var A=0x67452301;
var B=0xefcdab89;
var C=0x98badcfe;
var D=0x10325476;
res_size=size(res);
for(var i=0;i<res_size;i+=16){
var (f,a,b,c,d)=(0,A,B,C,D);
for(var j=0;j<64;j+=1){
f=functions[j](b,c,d);
(a,b,c,d)=(d,check(b+rol(a+f+K[j]+res[i+idx[j]],S[j])),b,c);
}
(A,B,C,D)=(check(a+A),check(b+B),check(c+C),check(d+D));
}
return hex32str(A)~hex32str(B)~hex32str(C)~hex32str(D);
};
}();
# check if md5 runs correctly
var md5check=func(){
var test_set=[
"md5",
"github.com",
"helloworld",
"abc",
"https://www.github.com/ValKmjolnir/Nasal-Interpreter",
"https://github.com/andyross/nasal",
"var (lower32,higher32)=(check(len),check(len/math.pow(2,32)));",
"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
"let the bass kick",
"f499377c9ae8454c6c8a21ddba7f00de5817fccdc611333ed004d826abb17f4efdacad297f72956e0619002cecffc8e3d18d9b03b082f3cb114bc29173954043",
"you are our last hope"
];
var result=[
"1bc29b36f623ba82aaf6724fd3b16718",
"99cd2175108d157588c04758296d1cfc",
"fc5e038d38a57032085441e7fe7010b0",
"900150983cd24fb0d6963f7d28e17f72",
"6b3a7bbc2240046c4fb1b0b3a4ed8181",
"14a6afca5f3a7b239c56b5a9678c428e",
"f499377c9ae8454c6c8a21ddba7f00de",
"fdacad297f72956e0619002cecffc8e3",
"16eadccb9799dfb4c1ca512f40638bbb",
"a7916c5ce54e73b7ddf6a286b36d976d",
"ec6d5b197ba019db23c719112f3f70b7"
];
forindex(var i;test_set){
var res=_md5(test_set[i]);
if(cmp(res,result[i]))
println(
"md5 cannot work:\n",
" test \""~test_set[i]~"\"\n",
" result \""~result[i]~"\"\n",
" but get \""~res~"\"\n"
);
}
}
# check when loading md5.nas
md5check();

132
test/md5compare.nas Normal file
View File

@@ -0,0 +1,132 @@
import("test/md5.nas");
srand();
var progress_bar=func(){
var res=[];
setsize(res,51);
var (tmp,sp)=(" |"," | ");
res[0]=tmp~sp;
for(var i=1;i<=50;i+=1){
tmp~="#";
res[i]=tmp~substr(sp,i,52-i);
}
return res;
}();
var compare=func(){
var ch=[
"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","+",
"_","*","/","\'","\"",".",",",";",":","<",">","!","@","#","$","%",
"^","&","*","(",")","-","=","\\","|","[","]","{","}","`"," ","\t","?"
];
return func(begin,end){
var (total,prt_cnt,lastpercent,percent)=(end-begin,0,0,0);
for(var i=begin;i<end;i+=1){
var s="";
for(var j=0;j<i;j+=1){
s~=ch[rand()*size(ch)];
}
var res=md5(s);
if(cmp(res,_md5(s))){
die("error: "~str(i));
}
percent=int((i-begin+1)/total*100);
if(percent-lastpercent>=2){
prt_cnt+=1;
lastpercent=percent;
}
print(progress_bar[prt_cnt],percent,"% (",i-begin+1,"/",total,")\t",res," max byte: ",end-1," \r");
}
print('\n');
};
}();
var filechecksum=func(){
var getname=func(s){
var (len,ch)=(size(s),' '[0]);
for(var i=0;i<len and s[i]!=ch;i+=1);
return substr(s,0,i);
}
var files=[
"./stl/file.nas ",
"./stl/lib.nas ",
"./stl/list.nas ",
"./stl/module.nas ",
"./stl/queue.nas ",
"./stl/result.nas ",
"./stl/sort.nas ",
"./stl/stack.nas ",
"./test/ascii-art.nas ",
"./test/auto_crash.nas ",
"./test/bf.nas ",
"./test/bfcolored.nas ",
"./test/bfconvertor.nas ",
"./test/bfs.nas ",
"./test/bigloop.nas ",
"./test/bp.nas ",
"./test/calc.nas ",
"./test/choice.nas ",
"./test/class.nas ",
"./test/diff.nas ",
"./test/exception.nas ",
"./test/fib.nas ",
"./test/filesystem.nas ",
"./test/hexdump.nas ",
"./test/json.nas ",
"./test/leetcode1319.nas ",
"./test/lexer.nas ",
"./test/life.nas ",
"./test/loop.nas ",
"./test/mandel.nas ",
"./test/mandelbrot.nas ",
"./test/md5.nas ",
"./test/md5compare.nas ",
"./test/module_test.nas ",
"./test/nasal_test.nas ",
"./test/pi.nas ",
"./test/prime.nas ",
"./test/props_sim.nas ",
"./test/props.nas ",
"./test/qrcode.nas ",
"./test/quick_sort.nas ",
"./test/scalar.nas ",
"./test/snake.nas ",
"./test/tetris.nas ",
"./test/trait.nas ",
"./test/turingmachine.nas",
"./test/utf8chk.nas ",
"./test/wavecollapse.nas ",
"./test/ycombinator.nas ",
"LICENSE ",
"main.cpp ",
"makefile ",
"nasal_ast.h ",
"nasal_builtin.h ",
"nasal_codegen.h ",
"nasal_dbg.h ",
"nasal_err.h ",
"nasal_gc.h ",
"nasal_import.h ",
"nasal_lexer.h ",
"nasal_opt.h ",
"nasal_parse.h ",
"nasal_vm.h ",
"nasal.ebnf ",
"nasal.h ",
"README.md "
];
foreach(var i;files){
var f=io.fin(getname(i));
var (res0,res1)=(md5(f),_md5(f));
println(i,' ',res0,' ',!cmp(res0,res1),' ',size(f),' byte');
}
}
var randomchecksum=func(){
for(var i=0;i<4096;i+=512)
compare(i,i+512);
}
filechecksum();
randomchecksum();

44
test/module_test.nas Normal file
View File

@@ -0,0 +1,44 @@
var libfib=func(){
var (dd,fib,qfib)=(nil,nil,nil);
return {
open:func(){
if(dd==nil){
dd=dylib.dlopen("./module/libfib.so");
fib=dylib.dlsym(dd,"fib");
qfib=dylib.dlsym(dd,"quick_fib");
}else{
println("[info ] already loaded.");
}
},
close:func(){
if(dd==nil){
println("[error ] already closed.");
return;
}
dylib.dlclose(dd);
(dd,fib,qfib)=(nil,nil,nil);
},
fib:func(x){
if(fib!=nil)
return dylib.dlcall(fib,x);
println("[error ] cannot call fib.");
return nil;
},
qfib:func(x){
if(qfib!=nil)
return dylib.dlcall(qfib,x);
println("[error ] cannot call qfib.");
return nil;
}
}
}();
println("[keys ] ",keys(libfib));
libfib.open();
libfib.open();
println("[result] ",libfib.fib(40));
println("[result] ",libfib.qfib(40));
libfib.close();
println("[result] ",libfib.fib(40));
println("[result] ",libfib.qfib(40));
libfib.close();

View File

@@ -1,6 +1,5 @@
# This is written for Nasal Intepreter
# Sidi Liang
import("lib.nas");
var w = 1;
var x = "hello";
var f = func(){
@@ -49,6 +48,6 @@ println(f);#//func(...){...}
f();#//f is called
println(z.funcc);#//func(...){...}
z.funcc();#//f is called
println(z.funcccall);#//nil
println(z.funcccall);#//func(...){...}
z2.listt2[3].hashh.funcc();#//f is called
println(y1[f2()][w]);#//hello

View File

@@ -1,9 +1,7 @@
import("lib.nas");
var (t,res)=(1,0);
for(var m=1;m<4e6;m+=2)
{
res+=t*1/m;
res+=t/m;
t=-t;
}
println(res*4);

38
test/prime.nas Normal file
View File

@@ -0,0 +1,38 @@
var is_prime=func(x){
for(var i=2;i<x;i+=1)
if(x/i==int(x/i))
return 0;
return 1;
}
var is_prime_sqrt=func(x){
for(var i=2;i<=math.sqrt(x);i+=1)
if(x/i==int(x/i))
return 0;
return 1;
}
var primes=[];
var filter=func(x){
foreach(var i;primes){
if(x/i==int(x/i))
return 0;
if(x>=i){
for(var j=i+1;j<=math.sqrt(x);j+=1)
if(x/j==int(x/j))
return 0;
append(primes,x);
return 1;
}
}
append(primes,x);
return 1;
}
func(){
var cnt=0;
for(var i=2;i<50000;i+=1)
if(filter(i))
cnt+=1;
println(cnt);
}();

View File

@@ -1,4 +1,26 @@
import("lib.nas");
var geodinfo=func(lat,lon){
return {};
}
var maketimer=func(interval,function){
return {
isRunning:0,
start:func(){
me.isRunning=1;
while(1){
unix.sleep(interval);
function();
}
},
stop:func(){
me.isRunning=0;
},
restart:func(interval){
},
singleShot:0,
simulatedTime:0
};
}
var props=
{
@@ -63,14 +85,14 @@ props.Node=
foreach(var label;path)
tmp=tmp.val[label];
tmp.val=val;
if(typeof(val)=='string')
if(typeof(val)=='str')
{
if(val=='true' or val=='false')
tmp.type='BOOL';
else
tmp.type='STRING';
}
elsif(typeof(val)=='number')
elsif(typeof(val)=='num')
tmp.type='DOUBLE';
return;
},
@@ -117,6 +139,11 @@ props.Node=
if(typeof(me.val)=='hash')
{
var key=keys(me.val);
if(!size(key))
{
println("{}");
return;
}
println('{');
foreach(var k;key)
{

63
test/qrcode.nas Normal file
View File

@@ -0,0 +1,63 @@
var code=[
[1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1],
[1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1],
[1,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1],
[1,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1],
[1,0,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,0,1],
[1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1],
[1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
];
if(os.platform()=="windows")
system("chcp 65001");
var texture=[" ","██"];
for(var i=0;i<size(code);i+=1){
for(var j=0;j<size(code[i]);j+=1)
print(texture[code[i][j]]);
print('\n');
}
var transfer=func(s){
var mode=[0,1,0,0];
println(mode);
var len=size(s);
var vec=[0,0,0,0,0,0,0,0,0];
for(var i=8;i>=0;i-=1){
vec[i]=bits.bitand(1,len);
len=int(len/2);
}
println(vec);
var bitstr=[];
for(var i=0;i<size(s);i+=1){
var tmp=[0,0,0,0,0,0,0,0];
var c=s[i];
for(var j=7;j>=0;j-=1){
tmp[j]=bits.bitand(1,c);
c=int(c/2);
}
foreach(var j;tmp)
append(bitstr,j);
}
println(bitstr);
var end=[0,0,0,0];
println(end);
}
transfer("github.com/ValKmjolnir");

View File

@@ -1,4 +1,3 @@
import("lib.nas");
var sort=func(vec,left,right)
{
if(left>=right) return;
@@ -19,7 +18,7 @@ var sort=func(vec,left,right)
}
var vec=[];
rand(time(0));
for(var i=0;i<200;i+=1)
append(vec,int(rand()*1000));
for(var i=0;i<1e4;i+=1)
append(vec,int(rand()*1e5));
sort(vec,0,size(vec)-1);
println(vec);

View File

@@ -1,5 +1,4 @@
# basic type
import("lib.nas");
nil;
2147483647;
0x7fffffff;
@@ -149,4 +148,56 @@ f1() or f2();
# print '1'
# this means that when using 'or' or 'and',
# if the result is clear when calculating,
# objects behind will not be calculated
# objects behind will not be calculated
print(
subvec([0,1,2,3],2),'\n',
subvec([0,1,2,3],2,1),'\n',
abs(1),'\n',
abs(-1),'\n',
systime(),'\n',
isfunc(func{}),' ',isfunc([]),'\n',
ishash({}),' ',ishash([]),'\n',
isint(114.514),' ',isint(114514),'\n',
isnum("0xaa55"),' ',isnum("?"),'\n',
isscalar(0.618),' ',isscalar("hello"),' ',isscalar([]),'\n',
isstr("hello"),' ',isstr(func{}),'\n',
isvec([]),' ',isvec("[]"),'\n',
vecindex([0,1,2,3,4],1),'\n',
vecindex(["apple","banana"],"apple")!=nil,'\n'
);
println(values({
a:1,
b:2,
c:3
}));
println(find("cd", "abcdef")); # prints 2
println(find("x", "abcdef")); # prints -1
println(find("cd", "abcdef")); # prints 2
var a={
new: func(x=0){
return {
x:x,
parents:[a]
};
},
new2: func(x=0){
return {
x:x,
parents:a
};
}
};
println(isa(a.new(),a)); # 1
println(isa(a.new2(),a));# 0
var a=[10,-10,0,1,2,3,nil,"string","hello",[],[0,1,2,3],{},{a:0,b:1,c:2},func{}];
println("type\tsize\tnum\tsrc");
foreach(var i;a){
println(typeof(i),'\t',size(i),'\t',num(i),'\t',i);
}
foreach(i;a){
;
}

216
test/snake.nas Normal file
View File

@@ -0,0 +1,216 @@
import("./module/libkey.nas");
var list=func(){
var (begin,end,len)=(nil,nil,0);
return{
push_back:func(elem){
var tmp={
elem:elem,
prev:nil,
next:nil
};
if(end!=nil){
end.next=tmp;
tmp.prev=end;
end=tmp;
}else{
begin=end=tmp;
}
len+=1;
},
push_front:func(elem){
var tmp={
elem:elem,
prev:nil,
next:nil
};
if(begin!=nil){
begin.prev=tmp;
tmp.next=begin;
begin=tmp;
}else{
begin=end=tmp;
}
len+=1;
},
pop_back:func(){
if(end!=nil)
end=end.prev;
if(end==nil)
begin=nil;
else
end.next=nil;
if(len)
len-=1;
},
pop_front:func(){
if(begin!=nil)
begin=begin.next;
if(begin==nil)
end=nil;
else
begin.prev=nil;
if(len)
len-=1;
},
front:func(){
if(begin!=nil)
return begin.elem;
},
back:func(){
if(end!=nil)
return end.elem;
},
length:func(){
return len;
}
};
}
var game=func(x,y){
rand(time(0));
var texture=[" ","██","\e[91m██\e[0m"];
var edge0="╔";
var edge1="╚";
for(var i=0;i<x;i+=1){
edge0~="══";
edge1~="══";
}
edge0~="╗\n";
edge1~="╝\n";
var vec=[];
setsize(vec,x);
for(var i=0;i<x;i+=1){
vec[i]=[];
setsize(vec[i],y);
for(var j=0;j<y;j+=1)
vec[i][j]=0;
}
var snake=list();
snake.push_back([int(x/2),int(y/3)]);
snake.push_back([int(x/2),int(y/3)+1]);
vec[int(x/2)][int(y/3)]=1;
vec[int(x/2)][int(y/3)+1]=1;
var move='w';
var gameover=0;
var setapple=func(){
var (cord_x,cord_y)=(int(rand()*x),int(rand()*y));
while(vec[cord_x][cord_y]!=0)
(cord_x,cord_y)=(int(rand()*x),int(rand()*y));
vec[cord_x][cord_y]=2;
}
setapple();
return {
print:func(){
var s="";
var (fx,fy)=snake.front();
for(var i=0;i<y;i+=1){
s~="║";
for(var j=0;j<x;j+=1){
if(fx==j and fy==i)
s~="\e[93m"~texture[vec[j][i]]~"\e[0m";
else
s~=texture[vec[j][i]];
}
s~='║\n';
}
print('\e[1;1H'~edge0~s~edge1);
},
next:func(){
var (fx,fy)=snake.front();
var eat=0;
if(move=="w" and fy-1>=0){
snake.push_front([fx,fy-1]);
if(vec[fx][fy-1]==1)
gameover=1;
elsif(vec[fx][fy-1]==2)
eat=1;
vec[fx][fy-1]=1;
}elsif(move=='a' and fx-1>=0){
snake.push_front([fx-1,fy]);
if(vec[fx-1][fy]==1)
gameover=1;
elsif(vec[fx-1][fy]==2)
eat=1;
vec[fx-1][fy]=1;
}elsif(move=='s' and fy+1<y){
snake.push_front([fx,fy+1]);
if(vec[fx][fy+1]==1)
gameover=1;
elsif(vec[fx][fy+1]==2)
eat=1;
vec[fx][fy+1]=1;
}elsif(move=='d' and fx+1<x){
snake.push_front([fx+1,fy]);
if(vec[fx+1][fy]==1)
gameover=1;
elsif(vec[fx+1][fy]==2)
eat=1;
vec[fx+1][fy]=1;
}else{
gameover=1;
}
if(!gameover and !eat){
var (bx,by)=snake.back();
vec[bx][by]=0;
snake.pop_back();
}
if(eat and snake.length()!=x*y)
setapple();
elsif(snake.length()==x*y)
gameover=2;
},
move:func(c){
if(c=='w' or c=='a' or c=='s' or c=='d')
move=c;
},
gameover:func(){
return gameover;
}
}
}
var main=func(){
if(os.platform()=="windows")
system("chcp 65001");
print("\ec");
libkey.init();
var g=game(15,10);
g.print();
print("\rpress any key to start...");
libkey.getch();
print("\r \r");
var counter=12;
while(1){
var ch=libkey.nonblock();
if(ch!=nil){
if(ch=='q'[0])
break;
elsif(ch=='p'[0]){
print("\rpress any key to continue...");
libkey.getch();
print("\r \r");
}
g.move(chr(ch));
}
unix.sleep(0.02);
counter-=1;
if(counter==0){
counter=20;
g.next();
if(g.gameover())
break;
g.print();
}
}
libkey.close();
println(g.gameover()<=1?"game over.":"you win!");
println("enter anything to quit.");
input();
}
main();

348
test/tetris.nas Normal file
View File

@@ -0,0 +1,348 @@
import("./module/libkey.nas");
var color=[
"\e[31m","\e[32m","\e[33m","\e[34m","\e[35m","\e[36m",
"\e[91m","\e[92m","\e[93m","\e[94m","\e[95m","\e[96m",
];
var blocktype=[
[0,1,2,3 ],
[4,5,6,7 ],
[8,9,10,11],
[12,13 ],
[14 ],
[15,16 ],
[17,18 ]
];
var blockshape=[
# [][] [] [][][]
# [] [] [] []
# [] [][][] [][]
[[0,0],[1,0],[0,1],[0,2]],
[[0,0],[0,1],[1,1],[2,1]],
[[0,0],[0,1],[0,2],[-1,2]],
[[0,0],[1,0],[2,0],[2,1]],
# [][] [][][] []
# [] [] [] []
# [] [][] [][][]
[[0,0],[1,0],[1,1],[1,2]],
[[0,0],[1,0],[2,0],[0,1]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[0,1],[-1,1],[-2,1]],
# [] [] [][][] []
# [][][] [][] [] [][]
# [] []
[[0,0],[0,1],[-1,1],[1,1]],
[[0,0],[0,1],[-1,1],[0,2]],
[[0,0],[-1,0],[1,0],[0,1]],
[[0,0],[0,1],[0,2],[1,1]],
# [] [][][][]
# []
# []
# []
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[1,0],[2,0],[3,0]],
# [][]
# [][]
[[0,0],[1,0],[0,1],[1,1]],
# [] [][]
# [][] [][]
# []
[[0,0],[0,1],[-1,1],[-1,2]],
[[0,0],[1,0],[1,1],[2,1]],
# [] [][]
# [][] [][]
# []
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[1,0],[0,1],[-1,1]]
];
var color_count=0;
var counter=0;
var package=[0,1,2,3,4,5,6];
var exchange=func(){
for(var i=6;i>=0;i-=1){
var index=int(i*rand());
(package[i],package[index])=(package[index],package[i]);
}
}
var block={
x:0,
y:0,
rotate:0,
type:nil,
shape:nil,
color:nil,
new:func(x=0,y=0){
(me.x,me.y)=(x,y);
me.rotate=0;
me.type=blocktype[package[counter]];
counter+=1;
if(counter==7){
exchange();
counter=0;
}
me.shape=blockshape[me.type[me.rotate]];
me.color=color_count;
color_count+=1;
if(color_count>=size(color))
color_count=0;
return {parents:[block]};
}
};
var mapgen=func(mapx,mapy){
var (score,gameover)=(0,0);
var (empty,unset,full)=(0,1,2);
if(mapx<1 or mapy<1)
die("map_x or map_y must be greater than 1");
# use in print
var line="";
for(var i=0;i<mapx;i+=1)
line~="══";
var head="\e[32m╔"~line~"╗\e[0m\n";
var tail="\e[32m╚"~line~"╝\e[0m\n";
# generate new map
var map=[];
for(var y=0;y<mapy;y+=1){
var tmp=[];
for(var x=0;x<mapx;x+=1)
append(tmp,empty);
append(map,tmp);
}
var blk=nil;
var new_block=func(){
blk=block.new(int(mapx/2),0);
# check if has enough place to place a new block
foreach(var i;blk.shape)
if(map[blk.y+i[1]][blk.x+i[0]]>=full){
gameover=1;
return;
}
# update map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
}
new_block(); # initialize the first block
# color print
var map_print=func(){
var s="\e[1;1H"~head;
for(var y=0;y<mapy;y+=1){
s~="\e[32m║\e[0m";
for(var x=0;x<mapx;x+=1){
var c=map[y][x];
if(c==empty)
s~=" ";
elsif(c==unset)
s~=color[blk.color]~"██\e[0m";
elsif(c>=full)
s~=color[c-full]~"██\e[0m";
}
s~="\e[32m║\e[0m\n";
}
s~=tail;
print(s,"\e[31ms\e[32mc\e[33mo\e[34mr\e[35me\e[36m: \e[0m",score,'\n');
}
var moveleft=func(){
var (x,y)=(blk.x-1,blk.y);
foreach(var i;blk.shape){
if(x+i[0]<0)
return;
if(map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.x=x;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var moveright=func(){
var (x,y)=(blk.x+1,blk.y);
foreach(var i;blk.shape){
if(x+i[0]>=mapx)
return;
if(map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.x=x;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var rotate=func(){
var (r,x,y)=(blk.rotate,blk.x,blk.y);
r=(r+1>=size(blk.type))?0:r+1;
var shape=blockshape[blk.type[r]];
foreach(var i;shape){
if(x+i[0]>=mapx or x+i[0]<0 or y+i[1]>=mapy or y+i[1]<0)
return;
if(map[y+i[1]][x+i[0]]>=full)
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.rotate=r;
blk.shape=shape;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var fall=func(){
var (x,y)=(blk.x,blk.y+1);
# check if falls to the edge of other blocks or map
var sethere=0;
foreach(var i;blk.shape)
if(y+i[1]>=mapy or map[y+i[1]][x+i[0]]>=full){
sethere=1;
break;
}
# set block here and generate a new block
if(sethere){
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=blk.color+full;
checkmap();
new_block();
map_print();
return;
}
# update block state and map
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=empty;
blk.y=y;
foreach(var i;blk.shape)
map[blk.y+i[1]][blk.x+i[0]]=unset;
map_print();
}
var checkmap=func(){
var lines=1;
for(var y=mapy-1;y>=0;y-=1){
# check if this line is full of blocks
var tmp=0;
for(var x=0;x<mapx;x+=1){
if(map[y][x]<full)
break;
tmp+=map[y][x];
}
# if is full, clear this line and
# all the lines above fall one block
if(x==mapx){
score+=lines*tmp;
lines*=2;
for(var t=y;t>=1;t-=1)
for(var x=0;x<mapx;x+=1)
map[t][x]=map[t-1][x];
for(var x=0;x<mapx;x+=1)
map[0][x]=empty;
y+=1;
}
}
map_print();
}
return {
print:map_print,
moveleft:moveleft,
moveright:moveright,
rotate:rotate,
fall:fall,
checkmap:checkmap,
gameover:func(){return gameover;}
};
}
var main=func(){
# windows use chcp 65001 to output unicode
if(os.platform()=="windows")
system("chcp 65001");
libkey.init();
print(
"\ec\e[1:1H",
"╔═════════════════════════╗\n",
"║ TETRIS ║\n",
"╠═════════════════════════╣\n",
"║ w:rotate, a:move left ║\n",
"║ s:fall, d:move right ║\n",
"║ p:pause, q:quit ║\n",
"╠═════════════════════════╣\n",
"║ press any key to start ║\n",
"╚═════════════════════════╝\n"
);
rand(time(0));
exchange();
var map=mapgen(mapx:12,mapy:18);
libkey.getch();
print("\ec");
var counter=30;
while(1){
# nonblock input one character
var ch=libkey.nonblock();
if(ch){
if(ch=='a'[0]) # move left
map.moveleft();
elsif(ch=='d'[0]) # move right
map.moveright();
elsif(ch=='w'[0]) # rotate
map.rotate();
elsif(ch=='s'[0]) # move down
map.fall();
elsif(ch=='q'[0]) # quit the game
break;
if(ch=='p'[0]){ # pause the game
print("\rpress any key to continue...");
libkey.getch();
print("\r ");
}
map.checkmap();
if(map.gameover())
break;
}
if(!counter){
# automatically fall one block and check
map.fall();
map.checkmap();
if(map.gameover())
break;
counter=30;
}
unix.sleep(0.02);
counter-=1;
}
libkey.close();
print(
map.gameover()?
"\e[31mg\e[32ma\e[33mm\e[34me \e[35mo\e[36mv\e[94me\e[31mr \e[32m~\e[0m\n":
"\e[31ms\e[32me\e[33me \e[34my\e[35mo\e[36mu \e[94m~\e[0m\n"
);
print(
"\e[31me\e[32mn\e[33mt\e[34me\e[35mr ",
"\e[36ma\e[94mn\e[95my\e[96mt\e[31mh\e[32mi\e[33mn\e[34mg ",
"\e[35mt\e[36mo \e[94mq\e[95mu\e[91mi\e[92mt\e[0m\n"
);
input();
};
main();

38
test/trait.nas Normal file
View File

@@ -0,0 +1,38 @@
var trait={
get:func{return me.val;},
set:func(x){me.val=x;}
};
var class={
new:func(){
return {
val:nil,
parents:[trait]
};
}
};
var class2={
new:func(){
return {
val:nil,
parents:[trait],
set:func(x){me.val=typeof(x);}
};
}
};
var class_obj=[];
for(var i=0;i<10;i+=1){
append(class_obj,class.new());
class_obj[i].set(i);
}
for(var i=0;i<10;i+=1){
append(class_obj,class2.new());
class_obj[10+i].set(i);
}
foreach(var object;class_obj){
println(object.get(),' ',keys(object));
}

100
test/turingmachine.nas Normal file
View File

@@ -0,0 +1,100 @@
var table=[
['q0','0','1','R','q1'],
['q1','1','1','R','q1'],
['q1','0','0','S','q2'],
['q2','0','1','R','q3'],
['q3',nil,nil,'S','q3']
];
var operand={
new:func(symbol,changed_symbol,move,next_state){
if(move!='L' and move!='R' and move!='S')
die("invalid move type:"+move);
return {
symbol:symbol,
changed_symbol:changed_symbol,
move:move,
next_state:next_state
};
}
};
var machine={
states:{},
add:func(state,operand){
if(!contains(me.states,state))
me.states[state]=[operand];
else{
foreach(var i;me.states[state])
if(i.symbol==operand.symbol or i.symbol==nil){
println(i);
die("conflict operand");
}
append(me.states[state],operand);
}
},
load:func(data){
foreach(var opr;data){
var (nstat,sym,csym,move,nextstat)=opr;
me.add(nstat,operand.new(sym,csym,move,nextstat));
}
}
};
var prt=func(state,pointer,paper,act=nil){
print(act!=nil?act:'','\n\t');
var s='';
foreach(var i;paper)
s~=i;
s~='\n\t';
for(var i=0;i<pointer;i+=1)
for(var j=0;j<size(paper[i]);j+=1)
s~=' ';
print(s,'^\n',state," ");
}
var run=func(table,start,stop){
var paper=['0','1','1','1','0','1','0','a'];
var pointer=0;
machine.load(table);
print("states: ",keys(machine.states),'\n');
if(!contains(machine.states,start))
die(start~" is not a valid node");
if(!contains(machine.states,stop))
die(stop~" is not a valid node");
var (state,pointer)=(start,0);
prt(state,pointer,paper);
while(state!=stop){
if(!contains(machine.states,state))
die("no matching function for state:"~state);
var found=0;
foreach(var action;machine.states[state]){
var (sym,csym,move,next)=(
action.symbol,
action.changed_symbol,
action.move,
action.next_state
);
if(sym==paper[pointer] or sym==nil){
if(sym!=nil)
paper[pointer]=csym;
if(move=='L') pointer-=1;
elsif(move=='R') pointer+=1;
(state,found)=(next,1);
break;
}
}
if(!found)
die("no matching function for state:"~state);
prt(state,pointer,paper,[sym,csym,move,next]);
}
}
run(table,'q0','q3');
print('\n');

32
test/utf8chk.nas Normal file
View File

@@ -0,0 +1,32 @@
var unicode测试=func(){
var 输出=print;
var 测试成功=[
"unicode: utf-8支持测试成功",
"目前仅支持utf-8以及ascii格式文件",
"注意: windows系统请开启chcp 65001代码页"
];
foreach(var 内容;测试成功)
输出(内容~"\n");
}
var emoji测试=func(){
var 💻=print;
var 🎤="\n";
var 🤣="🤣笑嘻了";
var 😅="😅差不多得了";
var 🤤="🤤收收味";
var 🥵="🥵太烧啦";
var 🥶="🥶捏麻麻滴冷死了";
var 🤢="🤢老八秘制小汉堡🍔";
var 🤓="🤓我是傻逼";
var 😭="😭你带我走吧😭😭😭";
var 👿="👿密麻麻石蜡";
var 🤡="🤡居然就是你";
var 💩="💩奥利给干了兄弟们";
var 🍾="🍾好似,开🍾咯";
var 🐘="🐘太🚬🐘了兄弟们";
var 📁=[🤣,😅,🤤,🥵,🥶,🤢,🤓,😭,👿,🤡,💩,🍾,🐘];
foreach(var 📄;📁)
💻(📄,🎤);
}
unicode测试();
emoji测试();

104
test/wavecollapse.nas Normal file
View File

@@ -0,0 +1,104 @@
# wave collapse function 2022/4/10
# by ValKmjolnir
srand();
var interval=1/60;
var table=[
# c ,w,a,s,d
["═",0,1,0,1],
["═",0,1,0,1],
["═",0,1,0,1],
["║",1,0,1,0],
["╔",0,0,1,1],
["╗",0,1,1,0],
["╚",1,0,0,1],
["╝",1,1,0,0],
# ["╠",1,0,1,1],
# ["╣",1,1,1,0],
# ["╦",0,1,1,1],
# ["╩",1,1,0,1],
# ["╬",1,1,1,1],
[" ",0,0,0,0],
[" ",0,0,0,0],
[" ",0,0,0,0],
[" ",0,0,0,0],
[" ",0,0,0,0],
[" ",0,0,0,0]
];
var map=func(){
var (vec,x,s)=(nil,nil,size(table));
var generator=func(){
var tmp=[];
foreach(var elem;table)
if(elem[1]==vec[0][0][3] and elem[2]==0)
append(tmp,elem);
vec[1][0]=tmp[rand()*size(tmp)];
for(var j=1;j<x;j+=1){
if(vec[0][j][3]==0 and vec[1][j-1][4]==0 and rand()>0.5){
vec[1][j]=table[-1];
continue;
}
tmp=[];
foreach(var elem;table)
if(elem[2]==vec[1][j-1][4] and elem[1]==vec[0][j][3]){
if((j==x-1 and elem[4]==0) or j<x-1)
append(tmp,elem);
}
vec[1][j]=tmp[rand()*size(tmp)];
}
}
return {
new:func(_x=10){
x=_x;
vec=[[],[]];
for(var i=0;i<2;i+=1){
setsize(vec[i],x);
for(var j=0;j<x;j+=1)
vec[i][j]=table[-1];
}
var tmp=[];
foreach(var elem;table)
if(elem[1]==0 and elem[2]==0)
append(tmp,elem);
vec[0][0]=tmp[rand()*size(tmp)];
for(var i=1;i<x;i+=1){
tmp=[];
foreach(var elem;table)
if(elem[2]==vec[0][i-1][4] and elem[1]==0){
if((i==x-1 and elem[4]==0) or i<x-1)
append(tmp,elem);
}
vec[0][i]=tmp[rand()*size(tmp)];
}
me.print(0);
generator();
},
print:func(index){
var str="";
foreach(var _x;vec[index])
str~=_x[0];
str~="\n";
print(str);
},
next:func(){
(vec[0],vec[1])=(vec[1],vec[0]);
generator();
}
}
}();
if(os.platform()=="windows")
system("chcp 65001");
map.new(80);
for(var iter=0;iter<100;iter+=1){
map.print(1);
map.next();
unix.sleep(interval);
}

15
test/ycombinator.nas Normal file
View File

@@ -0,0 +1,15 @@
# Y combinator by ValKmjolnir
var fib=func(f){
return f(f);
}(
func(f){
return func(x){
if(x<2) return x;
var tmp=f(f);
return tmp(x-1)+tmp(x-2);
}
}
);
for(var i=1;i<31;i+=1)
println(fib(i));