forked from xxq250/Nasal-Interpreter
Compare commits
197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d567f5abf8 | ||
|
|
f8692f1e4e | ||
|
|
712a047a43 | ||
|
|
396d55a207 | ||
|
|
c5171c735a | ||
|
|
07857d980c | ||
|
|
51a1279110 | ||
|
|
de262980cc | ||
|
|
23a5c1b1ad | ||
|
|
fd8a148d0c | ||
|
|
9c7f5f1a6e | ||
|
|
f049e1f9fb | ||
|
|
c4b7712e53 | ||
|
|
7417d5e635 | ||
|
|
785572634b | ||
|
|
2dc8459cbf | ||
|
|
6e035d1951 | ||
|
|
4f5fd3de33 | ||
|
|
fc25dd69e1 | ||
|
|
ca073499ae | ||
|
|
022460755f | ||
|
|
b6f174e869 | ||
|
|
7b160c4589 | ||
|
|
4503239731 | ||
|
|
c12e812651 | ||
|
|
87cff700e8 | ||
|
|
bf5737ecfd | ||
|
|
651ae4ef77 | ||
|
|
e846e51175 | ||
|
|
399b2f0ce9 | ||
|
|
aed5e27409 | ||
|
|
a2b51fe212 | ||
|
|
92b684624d | ||
|
|
83a8632e8e | ||
|
|
41b5304712 | ||
|
|
c5a12ade5c | ||
|
|
7a939b417d | ||
|
|
dd7740f1fd | ||
|
|
617ad03d33 | ||
|
|
b66ebbef4b | ||
|
|
7f22b25909 | ||
|
|
86f6296268 | ||
|
|
cf722fd98c | ||
|
|
1dd3fd445c | ||
|
|
27e25f84ec | ||
|
|
e6457651d3 | ||
|
|
c4d52a88cd | ||
|
|
9bcad59e45 | ||
|
|
9a099f66cb | ||
|
|
b79d60fab5 | ||
|
|
82e9e97a26 | ||
|
|
6a1338bb23 | ||
|
|
3b8a092f36 | ||
|
|
3d86a32b12 | ||
|
|
f26719e1d3 | ||
|
|
e54ef9620f | ||
|
|
d8156e839b | ||
|
|
61666d275d | ||
|
|
99f595e16f | ||
|
|
debe32b187 | ||
|
|
ca9b8581b4 | ||
|
|
a0b341deb5 | ||
|
|
d3df356299 | ||
|
|
cd808a5e6d | ||
|
|
40f61a9dd4 | ||
|
|
f312250d27 | ||
|
|
3fac8aa665 | ||
|
|
243aafd417 | ||
|
|
6bc03601d9 | ||
|
|
f05acaecc7 | ||
|
|
9456a903d7 | ||
|
|
984deed883 | ||
|
|
557cb2ebcf | ||
|
|
9c055a9a23 | ||
|
|
13a09343e6 | ||
|
|
8c67e04cc4 | ||
|
|
e77bb73a82 | ||
|
|
05fc5db337 | ||
|
|
a4738e8c7d | ||
|
|
5f6051e333 | ||
|
|
51afe3dacd | ||
|
|
0291908675 | ||
|
|
5fba784d05 | ||
|
|
9139e34c0b | ||
|
|
e7f503fae1 | ||
|
|
980350d70a | ||
|
|
0ccd3c9bd0 | ||
|
|
3e7ba4d774 | ||
|
|
a176022840 | ||
|
|
24a1e39ad3 | ||
|
|
a09c6ae2f9 | ||
|
|
2a85e92d4a | ||
|
|
92646840e4 | ||
|
|
c55ce758ed | ||
|
|
aa301aefc3 | ||
|
|
d6d90ab7c8 | ||
|
|
bf780514e6 | ||
|
|
eaa54035ff | ||
|
|
baa4f5a258 | ||
|
|
df24db5b58 | ||
|
|
4def93b4ad | ||
|
|
0a407437a4 | ||
|
|
05ab4640da | ||
|
|
b92eb4b089 | ||
|
|
5778d1e38d | ||
|
|
479e5a2c52 | ||
|
|
2f455c52c1 | ||
|
|
78c1f9b7a9 | ||
|
|
c68b4c5947 | ||
|
|
40344455e6 | ||
|
|
630c99c39a | ||
|
|
46716620e3 | ||
|
|
70a43c2f03 | ||
|
|
1923fc74e4 | ||
|
|
f0ae63bce5 | ||
|
|
30650bb64f | ||
|
|
d87aef82b7 | ||
|
|
e79d1eb8a4 | ||
|
|
189d49fa4a | ||
|
|
6a543f2aa7 | ||
|
|
c27c5b70ee | ||
|
|
0a246d2fc7 | ||
|
|
0956a08bec | ||
|
|
5a80258d20 | ||
|
|
85bb502191 | ||
|
|
ead49a657e | ||
|
|
df5be35af8 | ||
|
|
19d5952210 | ||
|
|
afd87da5e7 | ||
|
|
9861ecd03e | ||
|
|
aa191a9feb | ||
|
|
b8ef3cf6b6 | ||
|
|
0a8655eb4d | ||
|
|
52b49edbcf | ||
|
|
6a35c58df4 | ||
|
|
cd08b2d1bb | ||
|
|
f8e2918561 | ||
|
|
e4ea34db51 | ||
|
|
4bfce37f40 | ||
|
|
fd0d836c03 | ||
|
|
183446d32a | ||
|
|
540aeb73f4 | ||
|
|
4f0acc4d63 | ||
|
|
56280db2c7 | ||
|
|
885b57cd52 | ||
|
|
bbee31ea55 | ||
|
|
1bfa7d2638 | ||
|
|
d4a9412947 | ||
|
|
1b240b293e | ||
|
|
e41f728589 | ||
|
|
577546763f | ||
|
|
58ea303202 | ||
|
|
818685c48d | ||
|
|
5d13261516 | ||
|
|
56289b5d22 | ||
|
|
1733ac0573 | ||
|
|
d71b4f09e2 | ||
|
|
13d40e886e | ||
|
|
618ce59233 | ||
|
|
071d8bd1ce | ||
|
|
c498d5c8c4 | ||
|
|
11971267dc | ||
|
|
418531a44a | ||
|
|
59dc0d1423 | ||
|
|
385f0af17e | ||
|
|
ef9b781961 | ||
|
|
80cc8e9db7 | ||
|
|
b2be386be8 | ||
|
|
e4c598cae6 | ||
|
|
5fe6681b0d | ||
|
|
35fc848672 | ||
|
|
e3f3bd7387 | ||
|
|
638ec1c3a3 | ||
|
|
90ac468aa9 | ||
|
|
65dfef0a33 | ||
|
|
76a2548e95 | ||
|
|
40b690b67b | ||
|
|
2b17f3d702 | ||
|
|
5b6c78783e | ||
|
|
fa618eb97f | ||
|
|
d0616ef028 | ||
|
|
91771297d3 | ||
|
|
4e1a3c5f2d | ||
|
|
df634cb1b2 | ||
|
|
aa797142d1 | ||
|
|
816be43a98 | ||
|
|
9ebabfe737 | ||
|
|
884b56ac09 | ||
|
|
61677101e4 | ||
|
|
7a93f5b89b | ||
|
|
9fe7a86a3b | ||
|
|
9da029b8fe | ||
|
|
8b8e72c879 | ||
|
|
590c595522 | ||
|
|
57d6bcdc52 | ||
|
|
0b2fe61e6e | ||
|
|
706659ba3d |
34
.github/workflows/c-cpp.yml
vendored
Normal file
34
.github/workflows/c-cpp.yml
vendored
Normal 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
4
.gitignore
vendored
@@ -30,3 +30,7 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
nasal
|
||||
.vscode
|
||||
dump
|
||||
527
lib.nas
527
lib.nas
@@ -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
327
main.cpp
@@ -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
47
makefile
Normal 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
34
module/fib.cpp
Normal 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
74
module/keyboard.cpp
Normal 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
13
module/libfib.nas
Normal 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
47
module/libkey.nas
Normal 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
23
module/makefile
Normal 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"
|
||||
17
nasal.ebnf
17
nasal.ebnf
@@ -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
235
nasal.h
@@ -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
|
||||
|
||||
291
nasal_ast.h
291
nasal_ast.h
@@ -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
|
||||
1740
nasal_builtin.h
1740
nasal_builtin.h
File diff suppressed because it is too large
Load Diff
1544
nasal_codegen.h
1544
nasal_codegen.h
File diff suppressed because it is too large
Load Diff
295
nasal_dbg.h
Normal file
295
nasal_dbg.h
Normal 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, &¶, &&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
78
nasal_err.h
Normal 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
|
||||
600
nasal_gc.h
600
nasal_gc.h
@@ -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;
|
||||
}
|
||||
|
||||
278
nasal_import.h
278
nasal_import.h
@@ -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
|
||||
762
nasal_lexer.h
762
nasal_lexer.h
@@ -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
70
nasal_opt.h
Normal 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
|
||||
2033
nasal_parse.h
2033
nasal_parse.h
File diff suppressed because it is too large
Load Diff
1477
nasal_vm.h
1477
nasal_vm.h
File diff suppressed because it is too large
Load Diff
BIN
pic/benchmark.png
Normal file
BIN
pic/benchmark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
pic/mandelbrot.png
Normal file
BIN
pic/mandelbrot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
26
stl/file.nas
Normal file
26
stl/file.nas
Normal 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);}
|
||||
};
|
||||
}
|
||||
};
|
||||
527
stl/lib.nas
527
stl/lib.nas
@@ -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");
|
||||
}
|
||||
85
stl/list.nas
85
stl/list.nas
@@ -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
43
stl/module.nas
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -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
28
stl/result.nas
Normal 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]
|
||||
};
|
||||
};
|
||||
13
stl/sort.nas
13
stl/sort.nas
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
|
||||
75
test/bf.nas
75
test/bf.nas
@@ -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
242
test/bfcolored.nas
Normal 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);
|
||||
@@ -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;
|
||||
|
||||
33
test/bfs.nas
33
test/bfs.nas
@@ -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]);
|
||||
@@ -1 +1 @@
|
||||
for(var i=0;i<4e6;i+=1);
|
||||
for(var i=0;i<4e6;i+=1);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import("lib.nas");
|
||||
|
||||
rand(time(0));
|
||||
|
||||
var new_neuron=func()
|
||||
|
||||
128
test/calc.nas
128
test/calc.nas
@@ -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);
|
||||
@@ -1,4 +1,3 @@
|
||||
import("lib.nas");
|
||||
var condition_true=1;
|
||||
var condition_false=0;
|
||||
if(condition_true)
|
||||
|
||||
@@ -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
129
test/diff.nas
Normal 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
37
test/exception.nas
Normal 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();
|
||||
@@ -1,4 +1,3 @@
|
||||
import("lib.nas");
|
||||
var fib=func(x)
|
||||
{
|
||||
if(x<2) return x;
|
||||
|
||||
34
test/filesystem.nas
Normal file
34
test/filesystem.nas
Normal 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
84
test/hexdump.nas
Normal 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);
|
||||
}();
|
||||
476
test/json.nas
476
test/json.nas
@@ -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));
|
||||
@@ -1,4 +1,3 @@
|
||||
import("lib.nas");
|
||||
# union set
|
||||
var n=4;
|
||||
var input=[[0,1],[0,2],[1,2]];
|
||||
|
||||
181
test/lexer.nas
181
test/lexer.nas
@@ -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');
|
||||
@@ -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)
|
||||
|
||||
@@ -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
4808
test/mandel.nas
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
247
test/md5.nas
Normal 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
132
test/md5compare.nas
Normal 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
44
test/module_test.nas
Normal 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();
|
||||
@@ -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
|
||||
@@ -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
38
test/prime.nas
Normal 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);
|
||||
}();
|
||||
@@ -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
63
test/qrcode.nas
Normal 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");
|
||||
@@ -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);
|
||||
@@ -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
216
test/snake.nas
Normal 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
348
test/tetris.nas
Normal 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
38
test/trait.nas
Normal 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
100
test/turingmachine.nas
Normal 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
32
test/utf8chk.nas
Normal 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
104
test/wavecollapse.nas
Normal 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
15
test/ycombinator.nas
Normal 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));
|
||||
Reference in New Issue
Block a user