forked from xxq250/Nasal-Interpreter
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99189d4f95 | ||
|
|
ae16f36baa | ||
|
|
19ce1c5f34 | ||
|
|
7c026b62b7 | ||
|
|
9eb72f8754 | ||
|
|
73c9f98f4f | ||
|
|
09e5b3fa90 | ||
|
|
d8ce203ab3 | ||
|
|
71f501a323 | ||
|
|
a5825e0e92 | ||
|
|
230bbd5eb5 | ||
|
|
c9aa6cb6c4 | ||
|
|
789300e5f6 | ||
|
|
7f6a521ad7 | ||
|
|
14852bfc2e | ||
|
|
d0206abb8d | ||
|
|
35cd1bd1e2 | ||
|
|
1d941354ca | ||
|
|
2bb0f0bf47 | ||
|
|
c5d700d0bc | ||
|
|
33e544387e | ||
|
|
f336e5c3ae | ||
|
|
fce34c12b3 | ||
|
|
bbf5217374 | ||
|
|
ffdc8993c4 | ||
|
|
ab28657c78 | ||
|
|
f811368491 | ||
|
|
e9fd953273 | ||
|
|
4a5083f5cf | ||
|
|
1625f241fa | ||
|
|
d7f1de5d7f | ||
|
|
a0a22f701d | ||
|
|
5aabbd8d42 | ||
|
|
dc81773e7d | ||
|
|
405172b317 | ||
|
|
5c253bac88 | ||
|
|
2b4b1af72c | ||
|
|
a09b748093 | ||
|
|
fd8d3acfed | ||
|
|
b9a53b3c4a | ||
|
|
155ce6fc0d | ||
|
|
6f5143657e | ||
|
|
269d81ae5b | ||
|
|
2923d24e6c | ||
|
|
b612f73ff7 | ||
|
|
ab8db5dd62 | ||
|
|
e806b5f0a2 | ||
|
|
9a9277c505 | ||
|
|
67ae3505fb | ||
|
|
6daae85740 | ||
|
|
cc05fbb597 | ||
|
|
9958431b58 |
77
README.md
77
README.md
@@ -23,6 +23,10 @@ So i tried to write a new interpreter to help them checking syntax error and eve
|
||||
I wrote the lexer, parser and runtime(nasal virtual machine/ast-runtime virtual machine) to help checking errors.
|
||||
|
||||
They found it easier for them to check errors before copying nasal-codes in nasal-console in Flightgear to test.
|
||||
|
||||
# How to Compile
|
||||
|
||||
> g++ -std=c++11 main.cpp -o main.exe
|
||||
|
||||
# Lexical Analysis
|
||||
|
||||
@@ -30,43 +34,64 @@ The flow chart of lexer is here:
|
||||
|
||||
[](https://github.com/ValKmjolnir/Nasal-Interpreter/blob/master/pic/nasal_lexer.png)
|
||||
|
||||
This picture seems ugly. I will re-draw it later(maybe 1000 years later).
|
||||
|
||||
# Parser
|
||||
|
||||
## In __version 2.0__
|
||||
```javascript
|
||||
(var a,b,c)=(1,2,3);
|
||||
var (r,g,b)=color;
|
||||
```
|
||||
These two types of statements are both definition_expr.
|
||||
|
||||
```javascript
|
||||
(a,b,c)=(1,2,3);
|
||||
(a,b)=(b,a);
|
||||
```
|
||||
This type of statement is multi_assignment.
|
||||
|
||||
And to check if an expr in '(' ')' is multi_scalar or multi_id.
|
||||
|
||||
i used bool nasal_parse::check_multi_scalar() and bool nasal_parse::check_multi_assignment().
|
||||
|
||||
## In __version 3.0__
|
||||
## Version 3.0
|
||||
|
||||
I refactored parser and make it easier to maintain.
|
||||
|
||||
the EBNF is also refactored.
|
||||
The EBNF is also refactored.
|
||||
|
||||
# Abstract Syntax Tree
|
||||
|
||||
In __version 1.2__ the ast has been completed.
|
||||
## Version 1.2
|
||||
|
||||
In __version 3.0__ the ast is refactored and is now easier to read and maintain.
|
||||
The ast has been completed in this version.
|
||||
|
||||
# Version 2.0
|
||||
## Version 2.0
|
||||
|
||||
a completed ast-interpreter with unfinished lib functions.
|
||||
A completed ast-interpreter with unfinished lib functions.
|
||||
|
||||
# Version 3.0
|
||||
## Version 3.0
|
||||
|
||||
ast-interpreter uses new techniques so it can run codes more efficiently.
|
||||
The ast is refactored and is now easier to read and maintain.
|
||||
|
||||
byte-code-interpreter is in progress(i need a lot of time to learn that :( ).
|
||||
Ast-interpreter uses new techniques so it can run codes more efficiently.
|
||||
|
||||
Now you can add your own functions as builtin-functions in this interpreter!
|
||||
|
||||
I decide to save the ast interpreter after releasing v4.0. Because it took me a long time to think and write...
|
||||
|
||||
# Byte Code Interpreter
|
||||
|
||||
## Version 4.0
|
||||
|
||||
I have just finished the first version of byte-code-interpreter.
|
||||
|
||||
This interpreter is still in test.After this test,i will release version 4.0!
|
||||
|
||||
Now i am trying to search hidden bugs in this interpreter.Hope you could help me! :)
|
||||
|
||||
There's an example of byte code below:
|
||||
|
||||
```javascript
|
||||
var (a,b,c)=(1,2,3);
|
||||
```
|
||||
|
||||
```asm
|
||||
.number 1
|
||||
.number 2
|
||||
.number 3
|
||||
.symbol a
|
||||
.symbol b
|
||||
.symbol c
|
||||
0x00000000: pone 0x00000000
|
||||
0x00000001: load 0x00000000 (a)
|
||||
0x00000002: pnum 0x00000001 (2)
|
||||
0x00000003: load 0x00000001 (b)
|
||||
0x00000004: pnum 0x00000002 (3)
|
||||
0x00000005: load 0x00000002 (c)
|
||||
0x00000006: nop 0x00000000
|
||||
```
|
||||
8
lib.nas
8
lib.nas
@@ -86,10 +86,14 @@ var die=func(str)
|
||||
nasal_call_builtin_die(str);
|
||||
return nil;
|
||||
}
|
||||
var type=func(object)
|
||||
var typeof=func(object)
|
||||
{
|
||||
return nasal_call_builtin_type(object);
|
||||
}
|
||||
var substr=func(str,begin,length)
|
||||
{
|
||||
return nasal_call_builtin_substr(str,begin,length);
|
||||
}
|
||||
|
||||
var io=
|
||||
{
|
||||
@@ -131,7 +135,7 @@ var bits=
|
||||
var math=
|
||||
{
|
||||
e:2.7182818284590452354,
|
||||
pi:3.14159265358979323846,
|
||||
pi:3.14159265358979323846264338327950288,
|
||||
sin:func(x)
|
||||
{
|
||||
return nasal_call_builtin_sin(x);
|
||||
|
||||
129
main.cpp
129
main.cpp
@@ -1,25 +1,24 @@
|
||||
#include "nasal.h"
|
||||
|
||||
nasal_resource resource;
|
||||
nasal_lexer lexer;
|
||||
nasal_parse parse;
|
||||
nasal_import preprocessor;
|
||||
nasal_codegen code_generator;
|
||||
std::string command;
|
||||
nasal_import import;
|
||||
std::string inputfile="null";
|
||||
nasal_runtime runtime;
|
||||
nasal_codegen code_generator;
|
||||
nasal_bytecode_vm bytevm;
|
||||
|
||||
void help()
|
||||
{
|
||||
std::cout<<">> [\"file\"] input a file name.\n";
|
||||
std::cout<<">> [help ] show help.\n";
|
||||
std::cout<<">> [clear ] clear the screen.\n";
|
||||
std::cout<<">> [del ] clear the input filename.\n";
|
||||
std::cout<<">> [rs ] print source code.\n";
|
||||
std::cout<<">> [lex ] use lexer to turn code into tokens.\n";
|
||||
std::cout<<">> [ast ] do parsing and check the abstract syntax tree.\n";
|
||||
std::cout<<">> [run ] run abstract syntax tree.\n";
|
||||
std::cout<<">> [exec ] generate byte code.\n";
|
||||
std::cout<<">> [erun ] run byte code.\n";
|
||||
std::cout<<">> [code ] show byte code.\n";
|
||||
std::cout<<">> [exec ] execute program on bytecode vm.\n";
|
||||
std::cout<<">> [logo ] print logo of nasal .\n";
|
||||
std::cout<<">> [exit ] quit nasal interpreter.\n";
|
||||
return;
|
||||
@@ -37,7 +36,6 @@ void logo()
|
||||
|
||||
void del_func()
|
||||
{
|
||||
resource.clear();
|
||||
lexer.clear();
|
||||
parse.clear();
|
||||
inputfile="null";
|
||||
@@ -53,12 +51,8 @@ void die(std::string stage,std::string filename)
|
||||
|
||||
void lex_func()
|
||||
{
|
||||
if(!resource.input_file(inputfile))
|
||||
{
|
||||
die("resource",inputfile);
|
||||
return;
|
||||
}
|
||||
lexer.scanner(resource.get_file());
|
||||
lexer.openfile(inputfile);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
{
|
||||
die("lexer",inputfile);
|
||||
@@ -70,12 +64,8 @@ void lex_func()
|
||||
|
||||
void ast_print()
|
||||
{
|
||||
if(!resource.input_file(inputfile))
|
||||
{
|
||||
die("resource",inputfile);
|
||||
return;
|
||||
}
|
||||
lexer.scanner(resource.get_file());
|
||||
lexer.openfile(inputfile);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
{
|
||||
die("lexer",inputfile);
|
||||
@@ -91,14 +81,11 @@ void ast_print()
|
||||
parse.get_root().print_ast(0);
|
||||
return;
|
||||
}
|
||||
|
||||
void runtime_start()
|
||||
{
|
||||
if(!resource.input_file(inputfile))
|
||||
{
|
||||
die("resource",inputfile);
|
||||
return;
|
||||
}
|
||||
lexer.scanner(resource.get_file());
|
||||
lexer.openfile(inputfile);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
{
|
||||
die("lexer",inputfile);
|
||||
@@ -111,25 +98,21 @@ void runtime_start()
|
||||
die("parse",inputfile);
|
||||
return;
|
||||
}
|
||||
preprocessor.preprocessing(parse.get_root());
|
||||
if(preprocessor.get_error())
|
||||
import.link(parse.get_root());
|
||||
if(import.get_error())
|
||||
{
|
||||
die("import",inputfile);
|
||||
return;
|
||||
}
|
||||
runtime.set_root(preprocessor.get_root());
|
||||
runtime.set_root(import.get_root());
|
||||
runtime.run();
|
||||
return;
|
||||
}
|
||||
|
||||
void codegen_start()
|
||||
void show_bytecode()
|
||||
{
|
||||
if(!resource.input_file(inputfile))
|
||||
{
|
||||
die("resource",inputfile);
|
||||
return;
|
||||
}
|
||||
lexer.scanner(resource.get_file());
|
||||
lexer.openfile(inputfile);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
{
|
||||
die("lexer",inputfile);
|
||||
@@ -142,53 +125,57 @@ void codegen_start()
|
||||
die("parse",inputfile);
|
||||
return;
|
||||
}
|
||||
preprocessor.preprocessing(parse.get_root());
|
||||
if(preprocessor.get_error())
|
||||
import.link(parse.get_root());
|
||||
if(import.get_error())
|
||||
{
|
||||
die("import",inputfile);
|
||||
return;
|
||||
}
|
||||
runtime.set_root(preprocessor.get_root());
|
||||
code_generator.output_exec(inputfile+".naexec",preprocessor.get_root());
|
||||
if(code_generator.get_error())
|
||||
{
|
||||
die("code",inputfile);
|
||||
return;
|
||||
}
|
||||
code_generator.main_progress(import.get_root());
|
||||
code_generator.print_byte_code();
|
||||
return;
|
||||
}
|
||||
|
||||
void execution_start()
|
||||
void execute()
|
||||
{
|
||||
code_generator.load_exec(inputfile,preprocessor.get_root());
|
||||
if(code_generator.get_error())
|
||||
lexer.openfile(inputfile);
|
||||
lexer.scanner();
|
||||
if(lexer.get_error())
|
||||
{
|
||||
die("code",inputfile);
|
||||
die("lexer",inputfile);
|
||||
return;
|
||||
}
|
||||
runtime.set_root(preprocessor.get_root());
|
||||
runtime.run();
|
||||
parse.set_toklist(lexer.get_token_list());
|
||||
parse.main_process();
|
||||
if(parse.get_error())
|
||||
{
|
||||
die("parse",inputfile);
|
||||
return;
|
||||
}
|
||||
import.link(parse.get_root());
|
||||
if(import.get_error())
|
||||
{
|
||||
die("import",inputfile);
|
||||
return;
|
||||
}
|
||||
code_generator.main_progress(import.get_root());
|
||||
bytevm.run(
|
||||
code_generator.get_string_table(),
|
||||
code_generator.get_number_table(),
|
||||
code_generator.get_exec_code()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string command;
|
||||
#ifdef _WIN32
|
||||
// use chcp 65001 to use unicode io
|
||||
system("chcp 65001");
|
||||
system("cls");
|
||||
#endif
|
||||
logo();
|
||||
#ifdef _WIN32
|
||||
std::cout<<">> [system] Windows system.\n";
|
||||
#endif
|
||||
#ifdef _linux_
|
||||
std::cout<<">> [system] Linux system.\n";
|
||||
#endif
|
||||
#ifdef TARGET_OS_MAC
|
||||
std::cout<<">> [system] MacOS system.\n";
|
||||
#endif
|
||||
|
||||
std::cout<<">> Nasal interpreter ver 3.0 .\n";
|
||||
std::cout<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter\n";
|
||||
std::cout<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language\n";
|
||||
@@ -213,36 +200,22 @@ int main()
|
||||
}
|
||||
else if(command=="del")
|
||||
del_func();
|
||||
else if(command=="rs")
|
||||
{
|
||||
if(resource.input_file(inputfile))
|
||||
resource.print_file();
|
||||
}
|
||||
else if(command=="lex")
|
||||
lex_func();
|
||||
else if(command=="ast")
|
||||
ast_print();
|
||||
else if(command=="run")
|
||||
runtime_start();
|
||||
else if(command=="code")
|
||||
show_bytecode();
|
||||
else if(command=="exec")
|
||||
codegen_start();
|
||||
else if(command=="erun")
|
||||
execution_start();
|
||||
execute();
|
||||
else if(command=="logo")
|
||||
logo();
|
||||
else if(command=="exit")
|
||||
break;
|
||||
else
|
||||
{
|
||||
inputfile=command;
|
||||
std::ifstream fin(command);
|
||||
if(fin.fail())
|
||||
{
|
||||
std::cout<<">> [file] cannot open file \""<<command<<"\".\n";
|
||||
inputfile="null";
|
||||
}
|
||||
fin.close();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -59,11 +59,11 @@ multive_expr::=
|
||||
(unary|scalar) ('*' | '/') (unary|scalar)
|
||||
;
|
||||
unary::=
|
||||
('-'|'!') scalar
|
||||
('-'|'!') (unary|scalar)
|
||||
;
|
||||
scalar::=
|
||||
function {call_scalar}
|
||||
|identifier {call_scalar}
|
||||
|[func] identifier {call_scalar}
|
||||
|vector {call_scalar}
|
||||
|hash {call_scalar}
|
||||
|number
|
||||
|
||||
120
nasal.h
120
nasal.h
@@ -1,34 +1,140 @@
|
||||
#ifndef __NASAL_H__
|
||||
#define __NASAL_H__
|
||||
|
||||
#pragma GCC optimize(2)
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
/* if thread is used, don't forget to add -std=c++11 or higher standard before executing */
|
||||
// #include <thread>
|
||||
#include <thread>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "nasal_enum.h"
|
||||
#include "nasal_misc.h"
|
||||
#include "nasal_resource.h"
|
||||
/*
|
||||
check if a string can be converted to a number
|
||||
if this string cannot be converted to a number,it will return nan
|
||||
*/
|
||||
inline double hex_to_double(std::string str)
|
||||
{
|
||||
double ret=0;
|
||||
for(int i=2;str[i];++i)
|
||||
{
|
||||
ret*=16;
|
||||
if('0'<=str[i] && str[i]<='9')
|
||||
ret+=(str[i]-'0');
|
||||
else if('a'<=str[i] && str[i]<='f')
|
||||
ret+=(str[i]-'a'+10);
|
||||
else if('A'<=str[i] && str[i]<='F')
|
||||
ret+=(str[i]-'A'+10);
|
||||
else
|
||||
return std::nan("");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
inline double oct_to_double(std::string str)
|
||||
{
|
||||
double ret=0;
|
||||
for(int i=2;str[i];++i)
|
||||
{
|
||||
ret*=8;
|
||||
if('0'<=str[i] && str[i]<='8')
|
||||
ret+=(str[i]-'0');
|
||||
else
|
||||
return std::nan("");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
inline double dec_to_double(std::string str,int len)
|
||||
{
|
||||
double ret=0;
|
||||
int i=0;
|
||||
while('0'<=str[i] && str[i]<='9' && i<len)
|
||||
ret=ret*10+(str[i++]-'0');
|
||||
if(i==len) return ret;
|
||||
if(str[i]!='.' && str[i]!='e' && str[i]!='E')
|
||||
return std::nan("");
|
||||
if(str[i]=='.')
|
||||
{
|
||||
++i;
|
||||
if(i==len) return std::nan("");
|
||||
double num_pow=0.1;
|
||||
while('0'<=str[i] && str[i]<='9' && i<len)
|
||||
{
|
||||
ret+=num_pow*(str[i++]-'0');
|
||||
num_pow*=0.1;
|
||||
}
|
||||
}
|
||||
if(i==len) return ret;
|
||||
if(str[i]!='e' && str[i]!='E')
|
||||
return std::nan("");
|
||||
++i;
|
||||
if(i==len) return std::nan("");
|
||||
double negative=(str[i]=='-'? -1:1);
|
||||
if(str[i]=='-' || str[i]=='+')
|
||||
++i;
|
||||
if(i==len) return std::nan("");
|
||||
double num_pow=0;
|
||||
for(;i<len;++i)
|
||||
{
|
||||
if('0'<=str[i] && str[i]<='9')
|
||||
num_pow=num_pow*10+(str[i]-'0');
|
||||
else
|
||||
return std::nan("");
|
||||
}
|
||||
return ret*std::pow(10,negative*num_pow);
|
||||
}
|
||||
double trans_string_to_number(std::string str)
|
||||
{
|
||||
double is_negative=1;
|
||||
int len=str.length();
|
||||
double ret_num=0;
|
||||
if(!len) return std::nan("");
|
||||
if(str[0]=='-' || str[0]=='+')
|
||||
{
|
||||
if(len==1) return std::nan("");
|
||||
is_negative=(str[0]=='-'?-1:1);
|
||||
str=str.substr(1,len--);
|
||||
}
|
||||
if(len>1 && str[0]=='0' && str[1]=='x')
|
||||
ret_num=hex_to_double(str);
|
||||
else if(len>1 && str[0]=='0' && str[1]=='o')
|
||||
ret_num=oct_to_double(str);
|
||||
else
|
||||
ret_num=dec_to_double(str,len);
|
||||
return is_negative*ret_num;
|
||||
}
|
||||
|
||||
/*
|
||||
trans_number_to_string:
|
||||
convert number to string
|
||||
*/
|
||||
std::string trans_number_to_string(double number)
|
||||
{
|
||||
std::string res;
|
||||
std::stringstream ss;
|
||||
ss<<number;
|
||||
ss>>res;
|
||||
return res;
|
||||
}
|
||||
#include "nasal_lexer.h"
|
||||
#include "nasal_ast.h"
|
||||
#include "nasal_parse.h"
|
||||
#include "nasal_import.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_gc.h"
|
||||
#include "nasal_runtime.h"
|
||||
#include "nasal_builtin.h"
|
||||
#include "nasal_runtime.h"
|
||||
#include "nasal_codegen.h"
|
||||
#include "nasal_bytecode_vm.h"
|
||||
|
||||
#endif
|
||||
|
||||
124
nasal_ast.h
124
nasal_ast.h
@@ -1,15 +1,103 @@
|
||||
#ifndef __NASAL_AST_H__
|
||||
#define __NASAL_AST_H__
|
||||
|
||||
enum ast_node
|
||||
{
|
||||
ast_null=0,ast_root,ast_block,
|
||||
ast_nil,ast_number,ast_string,ast_identifier,ast_function,ast_hash,ast_vector,
|
||||
ast_hashmember,ast_call,ast_call_hash,ast_call_vec,ast_call_func,ast_subvec,
|
||||
ast_args,ast_default_arg,ast_dynamic_id,
|
||||
ast_and,ast_or,
|
||||
ast_equal,ast_add_equal,ast_sub_equal,ast_mult_equal,ast_div_equal,ast_link_equal,
|
||||
ast_cmp_equal,ast_cmp_not_equal,
|
||||
ast_less_than,ast_less_equal,
|
||||
ast_greater_than,ast_greater_equal,
|
||||
ast_add,ast_sub,ast_mult,ast_div,ast_link,
|
||||
ast_unary_sub,ast_unary_not,
|
||||
ast_trinocular,
|
||||
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_definition,ast_multi_assign,
|
||||
ast_continue,ast_break,ast_return
|
||||
};
|
||||
|
||||
std::string ast_str(int type)
|
||||
{
|
||||
std::string str;
|
||||
switch(type)
|
||||
{
|
||||
case ast_null: str="null";break;
|
||||
case ast_root: str="root";break;
|
||||
case ast_block: str="block";break;
|
||||
case ast_nil: str="nil";break;
|
||||
case ast_number: str="number";break;
|
||||
case ast_string: str="string";break;
|
||||
case ast_identifier: str="id";break;
|
||||
case ast_function: str="function";break;
|
||||
case ast_hash: str="hash";break;
|
||||
case ast_vector: str="vector";break;
|
||||
case ast_hashmember: str="hashmember";break;
|
||||
case ast_call: str="call";break;
|
||||
case ast_call_hash: str="call_hash";break;
|
||||
case ast_call_vec: str="call_vector";break;
|
||||
case ast_call_func: str="call_func";break;
|
||||
case ast_subvec: str="subvec";break;
|
||||
case ast_args: str="arguments";break;
|
||||
case ast_default_arg: str="default_arg";break;
|
||||
case ast_dynamic_id: str="dynamic_id";break;
|
||||
case ast_and: str="and";break;
|
||||
case ast_or: str="or";break;
|
||||
case ast_equal: str="=";break;
|
||||
case ast_add_equal: str="+=";break;
|
||||
case ast_sub_equal: str="-=";break;
|
||||
case ast_mult_equal: str="*=";break;
|
||||
case ast_div_equal: str="/=";break;
|
||||
case ast_link_equal: str="~=";break;
|
||||
case ast_cmp_equal: str="==";break;
|
||||
case ast_cmp_not_equal:str="!=";break;
|
||||
case ast_less_than: str="<";break;
|
||||
case ast_less_equal: str="<=";break;
|
||||
case ast_greater_than: str=">";break;
|
||||
case ast_greater_equal:str=">=";break;
|
||||
case ast_add: str="+";break;
|
||||
case ast_sub: str="-";break;
|
||||
case ast_mult: str="*";break;
|
||||
case ast_div: str="/";break;
|
||||
case ast_link: str="~";break;
|
||||
case ast_unary_sub: str="unary-";break;
|
||||
case ast_unary_not: str="unary!";break;
|
||||
case ast_trinocular: str="trinocular";break;
|
||||
case ast_for: str="for";break;
|
||||
case ast_forindex: str="forindex";break;
|
||||
case ast_foreach: str="foreach";break;
|
||||
case ast_while: str="while";break;
|
||||
case ast_new_iter: str="new_iterator";break;
|
||||
case ast_conditional: str="conditional";break;
|
||||
case ast_if: str="if";break;
|
||||
case ast_elsif: str="elsif";break;
|
||||
case ast_else: str="else";break;
|
||||
case ast_multi_id: str="multi_id";break;
|
||||
case ast_multi_scalar: str="multi_scalar";break;
|
||||
case ast_definition: str="definition";break;
|
||||
case ast_multi_assign: str="multi_assignment";break;
|
||||
case ast_continue: str="continue";break;
|
||||
case ast_break: str="break";break;
|
||||
case ast_return: str="return";break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
class nasal_ast
|
||||
{
|
||||
private:
|
||||
int line;
|
||||
int type;
|
||||
std::string str;
|
||||
double num;
|
||||
std::vector<nasal_ast> children;
|
||||
public:
|
||||
nasal_ast();
|
||||
nasal_ast(int,int);
|
||||
nasal_ast(const nasal_ast&);
|
||||
~nasal_ast();
|
||||
nasal_ast& operator=(const nasal_ast&);
|
||||
@@ -17,19 +105,20 @@ public:
|
||||
void set_line(int);
|
||||
void set_type(int);
|
||||
void set_str(std::string&);
|
||||
void set_num(double);
|
||||
void add_child(nasal_ast);
|
||||
int get_line();
|
||||
int get_type();
|
||||
int get_line();
|
||||
int get_type();
|
||||
std::string get_str();
|
||||
double get_num();
|
||||
std::vector<nasal_ast>& get_children();
|
||||
void print_ast(int);
|
||||
};
|
||||
|
||||
nasal_ast::nasal_ast()
|
||||
nasal_ast::nasal_ast(int init_line=0,int init_type=ast_null)
|
||||
{
|
||||
this->line=0;
|
||||
this->type=ast_null;
|
||||
this->str="";
|
||||
this->line=init_line;
|
||||
this->type=init_type;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -38,13 +127,13 @@ nasal_ast::nasal_ast(const nasal_ast& tmp)
|
||||
this->line=tmp.line;
|
||||
this->type=tmp.type;
|
||||
this->str=tmp.str;
|
||||
this->num=tmp.num;
|
||||
this->children=tmp.children;
|
||||
return;
|
||||
}
|
||||
|
||||
nasal_ast::~nasal_ast()
|
||||
{
|
||||
this->str.clear();
|
||||
this->children.clear();
|
||||
return;
|
||||
}
|
||||
@@ -54,6 +143,7 @@ nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
|
||||
this->line=tmp.line;
|
||||
this->type=tmp.type;
|
||||
this->str=tmp.str;
|
||||
this->num=tmp.num;
|
||||
this->children=tmp.children;
|
||||
return *this;
|
||||
}
|
||||
@@ -61,8 +151,9 @@ nasal_ast& nasal_ast::operator=(const nasal_ast& tmp)
|
||||
void nasal_ast::clear()
|
||||
{
|
||||
this->line=0;
|
||||
this->type=ast_null;
|
||||
this->str="";
|
||||
this->num=0;
|
||||
this->type=ast_null;
|
||||
this->children.clear();
|
||||
return;
|
||||
}
|
||||
@@ -85,6 +176,12 @@ void nasal_ast::set_str(std::string& s)
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_ast::set_num(double n)
|
||||
{
|
||||
this->num=n;
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_ast::add_child(nasal_ast ast)
|
||||
{
|
||||
children.push_back(ast);
|
||||
@@ -106,6 +203,11 @@ std::string nasal_ast::get_str()
|
||||
return this->str;
|
||||
}
|
||||
|
||||
double nasal_ast::get_num()
|
||||
{
|
||||
return this->num;
|
||||
}
|
||||
|
||||
std::vector<nasal_ast>& nasal_ast::get_children()
|
||||
{
|
||||
return this->children;
|
||||
@@ -117,8 +219,10 @@ void nasal_ast::print_ast(int depth)
|
||||
for(int i=0;i<depth;++i) indentation+="| ";
|
||||
indentation+=ast_str(this->type);
|
||||
std::cout<<indentation;
|
||||
if(this->type==ast_number || this->type==ast_string || this->type==ast_identifier || this->type==ast_dynamic_id || this->type==ast_call_hash)
|
||||
if(this->type==ast_string || this->type==ast_identifier || this->type==ast_dynamic_id || this->type==ast_call_hash)
|
||||
std::cout<<":"<<this->str;
|
||||
else if(this->type==ast_number)
|
||||
std::cout<<":"<<this->num;
|
||||
std::cout<<std::endl;
|
||||
int child_size=this->children.size();
|
||||
for(int i=0;i<child_size;++i)
|
||||
|
||||
430
nasal_builtin.h
430
nasal_builtin.h
@@ -1,17 +1,115 @@
|
||||
#ifndef __NASAL_BUILTIN_H__
|
||||
#define __NASAL_BUILTIN_H__
|
||||
|
||||
// builtin functions must be called inside a outer function like this:
|
||||
// var print=func(elements...)
|
||||
// {
|
||||
// nasal_call_builtin_std_cout(elements);
|
||||
// return nil;
|
||||
// }
|
||||
// builtin function nasal_call_builtin_std_cout is wrapped up by print
|
||||
|
||||
// used to find values that builtin function uses
|
||||
#define in_builtin_find(value_name_string) (local_scope_addr>=0?nasal_vm.gc_get(local_scope_addr).get_closure().get_value_address(value_name_string):-1)
|
||||
// used to check found value's type
|
||||
// types are:vm_nil vm_number vm_string vm_vector vm_hash vm_function
|
||||
// dynamic values will be generated as vector by the outer function
|
||||
#define in_builtin_check(value_addr,value_type) (nasal_vm.gc_get(value_addr).get_type()==(value_type))
|
||||
|
||||
int nasal_runtime::builtin_print(int local_scope_addr)
|
||||
// declaration of builtin functions
|
||||
// to add new builtin function,declare it here and write the definition below
|
||||
int builtin_print(int,nasal_virtual_machine&);
|
||||
int builtin_append(int,nasal_virtual_machine&);
|
||||
int builtin_setsize(int,nasal_virtual_machine&);
|
||||
int builtin_system(int,nasal_virtual_machine&);
|
||||
int builtin_input(int,nasal_virtual_machine&);
|
||||
int builtin_sleep(int,nasal_virtual_machine&);
|
||||
int builtin_finput(int,nasal_virtual_machine&);
|
||||
int builtin_foutput(int,nasal_virtual_machine&);
|
||||
int builtin_split(int,nasal_virtual_machine&);
|
||||
int builtin_rand(int,nasal_virtual_machine&);
|
||||
int builtin_id(int,nasal_virtual_machine&);
|
||||
int builtin_int(int,nasal_virtual_machine&);
|
||||
int builtin_num(int,nasal_virtual_machine&);
|
||||
int builtin_pop(int,nasal_virtual_machine&);
|
||||
int builtin_str(int,nasal_virtual_machine&);
|
||||
int builtin_size(int,nasal_virtual_machine&);
|
||||
int builtin_xor(int,nasal_virtual_machine&);
|
||||
int builtin_and(int,nasal_virtual_machine&);
|
||||
int builtin_or(int,nasal_virtual_machine&);
|
||||
int builtin_nand(int,nasal_virtual_machine&);
|
||||
int builtin_not(int,nasal_virtual_machine&);
|
||||
int builtin_sin(int,nasal_virtual_machine&);
|
||||
int builtin_cos(int,nasal_virtual_machine&);
|
||||
int builtin_tan(int,nasal_virtual_machine&);
|
||||
int builtin_exp(int,nasal_virtual_machine&);
|
||||
int builtin_ln(int,nasal_virtual_machine&);
|
||||
int builtin_sqrt(int,nasal_virtual_machine&);
|
||||
int builtin_atan2(int,nasal_virtual_machine&);
|
||||
int builtin_time(int,nasal_virtual_machine&);
|
||||
int builtin_contains(int,nasal_virtual_machine&);
|
||||
int builtin_delete(int,nasal_virtual_machine&);
|
||||
int builtin_getkeys(int,nasal_virtual_machine&);
|
||||
int builtin_import(int,nasal_virtual_machine&);
|
||||
bool builtin_die_state;// used in builtin_die
|
||||
int builtin_die(int,nasal_virtual_machine&);
|
||||
int builtin_type(int,nasal_virtual_machine&);
|
||||
int builtin_substr(int,nasal_virtual_machine&);
|
||||
|
||||
// register builtin function's name and it's address here in this table below
|
||||
// this table must and with {"",NULL}
|
||||
struct FUNC_TABLE
|
||||
{
|
||||
std::string func_name;
|
||||
int (*func_pointer)(int x,nasal_virtual_machine& nasal_vm);
|
||||
} builtin_func_table[]=
|
||||
{
|
||||
{"nasal_call_builtin_std_cout", builtin_print},
|
||||
{"nasal_call_builtin_push_back", builtin_append},
|
||||
{"nasal_call_builtin_set_size", builtin_setsize},
|
||||
{"nasal_call_builtin_system", builtin_system},
|
||||
{"nasal_call_builtin_input", builtin_input},
|
||||
{"nasal_call_builtin_sleep", builtin_sleep},
|
||||
{"nasal_call_builtin_finput", builtin_finput},
|
||||
{"nasal_call_builtin_foutput", builtin_foutput},
|
||||
{"nasal_call_builtin_split", builtin_split},
|
||||
{"nasal_call_builtin_rand", builtin_rand},
|
||||
{"nasal_call_builtin_get_id", builtin_id},
|
||||
{"nasal_call_builtin_trans_int", builtin_int},
|
||||
{"nasal_call_builtin_trans_num", builtin_num},
|
||||
{"nasal_call_builtin_pop_back", builtin_pop},
|
||||
{"nasal_call_builtin_trans_str", builtin_str},
|
||||
{"nasal_call_builtin_size", builtin_size},
|
||||
{"nasal_call_builtin_xor", builtin_xor},
|
||||
{"nasal_call_builtin_and", builtin_and},
|
||||
{"nasal_call_builtin_or", builtin_or},
|
||||
{"nasal_call_builtin_nand", builtin_nand},
|
||||
{"nasal_call_builtin_not", builtin_not},
|
||||
{"nasal_call_builtin_sin", builtin_sin},
|
||||
{"nasal_call_builtin_cos", builtin_cos},
|
||||
{"nasal_call_builtin_tan", builtin_tan},
|
||||
{"nasal_call_builtin_exp", builtin_exp},
|
||||
{"nasal_call_builtin_cpp_math_ln", builtin_ln},
|
||||
{"nasal_call_builtin_cpp_math_sqrt", builtin_sqrt},
|
||||
{"nasal_call_builtin_cpp_atan2", builtin_atan2},
|
||||
{"nasal_call_builtin_time", builtin_time},
|
||||
{"nasal_call_builtin_contains", builtin_contains},
|
||||
{"nasal_call_builtin_delete", builtin_delete},
|
||||
{"nasal_call_builtin_get_keys", builtin_getkeys},
|
||||
{"nasal_call_import", builtin_import},
|
||||
{"nasal_call_builtin_die", builtin_die},
|
||||
{"nasal_call_builtin_type", builtin_type},
|
||||
{"nasal_call_builtin_substr", builtin_substr},
|
||||
{"", NULL}
|
||||
};
|
||||
|
||||
int builtin_print(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
// get arguments
|
||||
int vector_value_addr=in_builtin_find("elements");
|
||||
if(vector_value_addr<0 || !in_builtin_check(vector_value_addr,vm_vector))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_print: \"elements\" has wrong value type(must be vector).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
// main process
|
||||
@@ -25,33 +123,28 @@ int nasal_runtime::builtin_print(int local_scope_addr)
|
||||
case vm_nil:std::cout<<"nil";break;
|
||||
case vm_number:std::cout<<tmp.get_number();break;
|
||||
case vm_string:std::cout<<tmp.get_string();break;
|
||||
case vm_vector:std::cout<<"[...]";break;
|
||||
case vm_hash:std::cout<<"{...}";break;
|
||||
case vm_vector:tmp.get_vector().print();break;
|
||||
case vm_hash:tmp.get_hash().print();break;
|
||||
case vm_function:std::cout<<"func(...){...}";break;
|
||||
case vm_closure:std::cout<<"closure{{...}}";break;
|
||||
}
|
||||
if(i==size-1)
|
||||
std::cout<<'\n';
|
||||
}
|
||||
std::cout<<"\n";
|
||||
// generate return value
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_append(int local_scope_addr)
|
||||
int builtin_append(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int vector_value_addr=in_builtin_find("vector");
|
||||
int elem_value_addr=in_builtin_find("elements");
|
||||
if(vector_value_addr<0 || !in_builtin_check(vector_value_addr,vm_vector))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_append: \"vector\" has wrong value type(must be vector).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(elem_value_addr<0 || !in_builtin_check(elem_value_addr,vm_vector))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_append: \"elements\" has wrong value type(must be vector).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
nasal_vector& ref_vector=nasal_vm.gc_get(vector_value_addr).get_vector();
|
||||
@@ -63,31 +156,27 @@ int nasal_runtime::builtin_append(int local_scope_addr)
|
||||
nasal_vm.add_reference(value_address);
|
||||
ref_vector.add_elem(value_address);
|
||||
}
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_setsize(int local_scope_addr)
|
||||
int builtin_setsize(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int vector_value_addr=in_builtin_find("vector");
|
||||
int size_value_addr=in_builtin_find("size");
|
||||
if(vector_value_addr<0 || nasal_vm.gc_get(vector_value_addr).get_type()!=vm_vector)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_setsize: \"vector\" has wrong value type(must be vector).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(size_value_addr<0)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_setsize: \"size\" has wrong value type(must be string or number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int type=nasal_vm.gc_get(size_value_addr).get_type();
|
||||
if(type!=vm_number && type!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_setsize: size is not a number.\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number;
|
||||
@@ -96,19 +185,17 @@ int nasal_runtime::builtin_setsize(int local_scope_addr)
|
||||
else
|
||||
{
|
||||
std::string str=nasal_vm.gc_get(size_value_addr).get_string();
|
||||
if(check_numerable_string(str))
|
||||
number=(int)trans_string_to_number(str);
|
||||
else
|
||||
double tmp=trans_string_to_number(str);
|
||||
if(std::isnan(tmp))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_setsize: size is not a numerable string.\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
number=(int)tmp;
|
||||
}
|
||||
if(number<0)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_setsize: size must be greater than -1.\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
nasal_vector& ref_vector=nasal_vm.gc_get(vector_value_addr).get_vector();
|
||||
@@ -123,22 +210,19 @@ int nasal_runtime::builtin_setsize(int local_scope_addr)
|
||||
else if(number>vec_size)
|
||||
for(int i=vec_size;i<number;++i)
|
||||
{
|
||||
int new_val_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(new_val_addr).set_type(vm_nil);
|
||||
int new_val_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
ref_vector.add_elem(new_val_addr);
|
||||
}
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
int nasal_runtime::builtin_system(int local_scope_addr)
|
||||
int builtin_system(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int str_value_addr=in_builtin_find("str");
|
||||
if(str_value_addr<0 || nasal_vm.gc_get(str_value_addr).get_type()!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_system: \"str\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string str=nasal_vm.gc_get(str_value_addr).get_string();
|
||||
@@ -149,58 +233,51 @@ int nasal_runtime::builtin_system(int local_scope_addr)
|
||||
command[size]='\0';
|
||||
system(command);
|
||||
delete []command;
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
int nasal_runtime::builtin_input(int local_scope_addr)
|
||||
int builtin_input(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_string);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_string);
|
||||
std::string str;
|
||||
std::cin>>str;
|
||||
nasal_vm.gc_get(ret_addr).set_string(str);
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
int nasal_runtime::builtin_sleep(int local_scope_addr)
|
||||
int builtin_sleep(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("duration");
|
||||
if(value_addr<0 || (nasal_vm.gc_get(value_addr).get_type()!=vm_string && nasal_vm.gc_get(value_addr).get_type()!=vm_number))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_sleep: \"duration\" has wrong value type(must be string or number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
unsigned long sleep_time=0;
|
||||
if(nasal_vm.gc_get(value_addr).get_type()==vm_string)
|
||||
{
|
||||
std::string str=nasal_vm.gc_get(value_addr).get_string();
|
||||
if(check_numerable_string(str))
|
||||
sleep_time=(unsigned long)trans_string_to_number(str);
|
||||
else
|
||||
double number=trans_string_to_number(str);
|
||||
if(std::isnan(number))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_sleep: this is not a numerable string.\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
}sleep_time=(unsigned long)number;
|
||||
}
|
||||
else
|
||||
sleep_time=(unsigned long)nasal_vm.gc_get(value_addr).get_number();
|
||||
sleep(sleep_time); // sleep in unistd.h will make this progress sleep sleep_time seconds.
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
int nasal_runtime::builtin_finput(int local_scope_addr)
|
||||
int builtin_finput(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("filename");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_finput: \"filename\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string filename=nasal_vm.gc_get(value_addr).get_string();
|
||||
@@ -209,33 +286,31 @@ int nasal_runtime::builtin_finput(int local_scope_addr)
|
||||
if(!fin.fail())
|
||||
while(!fin.eof())
|
||||
{
|
||||
file_content.push_back(fin.get());
|
||||
char c=fin.get();
|
||||
if(fin.eof())
|
||||
break;
|
||||
file_content.push_back(c);
|
||||
}
|
||||
else
|
||||
file_content="cannot open file named \'"+filename+"\'.";
|
||||
file_content="";
|
||||
fin.close();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_string);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_string);
|
||||
nasal_vm.gc_get(ret_addr).set_string(file_content);
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
int nasal_runtime::builtin_foutput(int local_scope_addr)
|
||||
int builtin_foutput(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("filename");
|
||||
int str_value_addr=in_builtin_find("str");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_foutput: \"filename\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(str_value_addr<0 || nasal_vm.gc_get(str_value_addr).get_type()!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_foutput: \"str\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string filename=nasal_vm.gc_get(value_addr).get_string();
|
||||
@@ -243,42 +318,46 @@ int nasal_runtime::builtin_foutput(int local_scope_addr)
|
||||
std::ofstream fout(filename);
|
||||
fout<<file_content;
|
||||
fout.close();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
int nasal_runtime::builtin_split(int local_scope_addr)
|
||||
int builtin_split(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int delimeter_value_addr=in_builtin_find("delimeter");
|
||||
int string_value_addr=in_builtin_find("string");
|
||||
if(delimeter_value_addr<0 || nasal_vm.gc_get(delimeter_value_addr).get_type()!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_split: \"delimeter\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(string_value_addr<0 || nasal_vm.gc_get(string_value_addr).get_type()!=vm_string)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_split: \"string\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string delimeter=nasal_vm.gc_get(delimeter_value_addr).get_string();
|
||||
std::string source=nasal_vm.gc_get(string_value_addr).get_string();
|
||||
int delimeter_len=delimeter.length();
|
||||
if(delimeter_len<1)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_split: delimeter's length must be greater than 0.\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int source_len=source.length();
|
||||
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_vector);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_vector);
|
||||
nasal_vector& ref_vec=nasal_vm.gc_get(ret_addr).get_vector();
|
||||
std::string tmp="";
|
||||
|
||||
if(!delimeter_len)
|
||||
{
|
||||
for(int i=0;i<source_len;++i)
|
||||
{
|
||||
tmp+=source[i];
|
||||
int str_addr=nasal_vm.gc_alloc(vm_string);
|
||||
nasal_vm.gc_get(str_addr).set_string(tmp);
|
||||
ref_vec.add_elem(str_addr);
|
||||
tmp="";
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
for(int i=0;i<source_len;++i)
|
||||
{
|
||||
bool check_delimeter=false;
|
||||
@@ -292,8 +371,7 @@ int nasal_runtime::builtin_split(int local_scope_addr)
|
||||
}
|
||||
if(check_delimeter)
|
||||
{
|
||||
int str_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(str_addr).set_type(vm_string);
|
||||
int str_addr=nasal_vm.gc_alloc(vm_string);
|
||||
nasal_vm.gc_get(str_addr).set_string(tmp);
|
||||
ref_vec.add_elem(str_addr);
|
||||
tmp="";
|
||||
@@ -304,124 +382,103 @@ int nasal_runtime::builtin_split(int local_scope_addr)
|
||||
}
|
||||
if(tmp.length())
|
||||
{
|
||||
int str_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(str_addr).set_type(vm_string);
|
||||
int str_addr=nasal_vm.gc_alloc(vm_string);
|
||||
nasal_vm.gc_get(str_addr).set_string(tmp);
|
||||
ref_vec.add_elem(str_addr);
|
||||
tmp="";
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_rand(int local_scope_addr)
|
||||
int builtin_rand(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("seed");
|
||||
if(value_addr<0 || (nasal_vm.gc_get(value_addr).get_type()!=vm_number && nasal_vm.gc_get(value_addr).get_type()!=vm_nil))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_rand: \"seed\" has wrong value type(must be nil or number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(nasal_vm.gc_get(value_addr).get_type()==vm_number)
|
||||
{
|
||||
unsigned int number=(unsigned int)nasal_vm.gc_get(value_addr).get_number();
|
||||
srand(number);
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
double num=0;
|
||||
for(int i=0;i<5;++i)
|
||||
num=(num+rand())*(1.0/(RAND_MAX+1.0));
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(num);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_id(int local_scope_addr)
|
||||
int builtin_id(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("id");
|
||||
int value_addr=in_builtin_find("thing");
|
||||
if(value_addr<0)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_id: cannot find \"id\".\n";
|
||||
++error;
|
||||
std::cout<<">> [runtime] builtin_id: cannot find \"thing\".\n";
|
||||
return -1;
|
||||
}
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)value_addr);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_int(int local_scope_addr)
|
||||
int builtin_int(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("value");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_int: \"value\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number=(int)nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)number);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_num(int local_scope_addr)
|
||||
int builtin_num(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("value");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_string)
|
||||
if(value_addr<0 || !in_builtin_check(value_addr,vm_string))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_num: \"value\" has wrong value type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string str=nasal_vm.gc_get(value_addr).get_string();
|
||||
if(!check_numerable_string(str))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_num: this is not a numerable string.\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=trans_string_to_number(str);
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(trans_string_to_number(str));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_pop(int local_scope_addr)
|
||||
int builtin_pop(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("vector");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_vector)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_pop: \"vector\" has wrong value type(must be vector).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int ret_addr=nasal_vm.gc_get(value_addr).get_vector().del_elem();
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_str(int local_scope_addr)
|
||||
int builtin_str(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("number");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_str: \"number\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_string);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_string(trans_number_to_string(number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_size(int local_scope_addr)
|
||||
int builtin_size(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("object");
|
||||
if(value_addr<0)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_size: cannot find value \"object\".\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int type=nasal_vm.gc_get(value_addr).get_type();
|
||||
@@ -436,345 +493,301 @@ int nasal_runtime::builtin_size(int local_scope_addr)
|
||||
case vm_vector:number=nasal_vm.gc_get(value_addr).get_vector().size();break;
|
||||
case vm_hash:number=nasal_vm.gc_get(value_addr).get_hash().size();break;
|
||||
}
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
int ret_addr=-1;
|
||||
if(number<0)
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
else
|
||||
{
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)number);
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_xor(int local_scope_addr)
|
||||
int builtin_xor(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int a_addr=in_builtin_find("a");
|
||||
int b_addr=in_builtin_find("b");
|
||||
if(a_addr<0 || nasal_vm.gc_get(a_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_xor: \"a\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(b_addr<0 || nasal_vm.gc_get(b_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_xor: \"b\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number_a=(int)nasal_vm.gc_get(a_addr).get_number();
|
||||
int number_b=(int)nasal_vm.gc_get(b_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)(number_a^number_b));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_and(int local_scope_addr)
|
||||
int builtin_and(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int a_addr=in_builtin_find("a");
|
||||
int b_addr=in_builtin_find("b");
|
||||
if(a_addr<0 || nasal_vm.gc_get(a_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_and: \"a\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(b_addr<0 || nasal_vm.gc_get(b_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_and: \"b\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number_a=(int)nasal_vm.gc_get(a_addr).get_number();
|
||||
int number_b=(int)nasal_vm.gc_get(b_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)(number_a&number_b));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_or(int local_scope_addr)
|
||||
int builtin_or(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int a_addr=in_builtin_find("a");
|
||||
int b_addr=in_builtin_find("b");
|
||||
if(a_addr<0 || nasal_vm.gc_get(a_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_or: \"a\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(b_addr<0 || nasal_vm.gc_get(b_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_or: \"b\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number_a=(int)nasal_vm.gc_get(a_addr).get_number();
|
||||
int number_b=(int)nasal_vm.gc_get(b_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)(number_a|number_b));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_nand(int local_scope_addr)
|
||||
int builtin_nand(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int a_addr=in_builtin_find("a");
|
||||
int b_addr=in_builtin_find("b");
|
||||
if(a_addr<0 || nasal_vm.gc_get(a_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_nand: \"a\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(b_addr<0 || nasal_vm.gc_get(b_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_nand: \"b\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number_a=(int)nasal_vm.gc_get(a_addr).get_number();
|
||||
int number_b=(int)nasal_vm.gc_get(b_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)(~(number_a&number_b)));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_not(int local_scope_addr)
|
||||
int builtin_not(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int a_addr=in_builtin_find("a");
|
||||
if(a_addr<0 || nasal_vm.gc_get(a_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_not: \"a\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int number=(int)nasal_vm.gc_get(a_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)(~number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_sin(int local_scope_addr)
|
||||
int builtin_sin(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("x");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_sin: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(sin(number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_cos(int local_scope_addr)
|
||||
int builtin_cos(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("x");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_cos: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(cos(number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_tan(int local_scope_addr)
|
||||
int builtin_tan(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("x");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_tan: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(tan(number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_exp(int local_scope_addr)
|
||||
int builtin_exp(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("x");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_exp: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(exp(number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_ln(int local_scope_addr)
|
||||
int builtin_ln(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("x");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_ln: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(log(number)/log(2.7182818284590452354));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_sqrt(int local_scope_addr)
|
||||
int builtin_sqrt(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("x");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_sqrt: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double number=nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(sqrt(number));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_atan2(int local_scope_addr)
|
||||
int builtin_atan2(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int x_value_addr=in_builtin_find("x");
|
||||
int y_value_addr=in_builtin_find("y");
|
||||
if(x_value_addr<0 || nasal_vm.gc_get(x_value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_atan2: \"x\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(y_value_addr<0 || nasal_vm.gc_get(y_value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_atan2: \"y\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
double x=nasal_vm.gc_get(x_value_addr).get_number();
|
||||
double y=nasal_vm.gc_get(y_value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number(atan2(y,x));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_time(int local_scope_addr)
|
||||
int builtin_time(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("begin_time");
|
||||
if(value_addr<0 || nasal_vm.gc_get(value_addr).get_type()!=vm_number)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_time: \"begin_time\" has wrong value type(must be number).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
time_t begin_time=(time_t)nasal_vm.gc_get(value_addr).get_number();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)time(&begin_time));
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_contains(int local_scope_addr)
|
||||
int builtin_contains(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int hash_addr=in_builtin_find("hash");
|
||||
int key_addr=in_builtin_find("key");
|
||||
if(hash_addr<0 || !in_builtin_check(hash_addr,vm_hash))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_contains: \"hash\" has wrong type(must be hash).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(key_addr<0 || !in_builtin_check(key_addr,vm_string))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_contains: \"key\" has wrong type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string key=nasal_vm.gc_get(key_addr).get_string();
|
||||
bool contains=nasal_vm.gc_get(hash_addr).get_hash().check_contain(key);
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_number);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_number);
|
||||
nasal_vm.gc_get(ret_addr).set_number((double)contains);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_delete(int local_scope_addr)
|
||||
int builtin_delete(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int hash_addr=in_builtin_find("hash");
|
||||
int key_addr=in_builtin_find("key");
|
||||
if(hash_addr<0 || !in_builtin_check(hash_addr,vm_hash))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_delete: \"hash\" has wrong type(must be hash).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
if(key_addr<0 || !in_builtin_check(key_addr,vm_string))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_delete: \"key\" has wrong type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
std::string key=nasal_vm.gc_get(key_addr).get_string();
|
||||
nasal_vm.gc_get(hash_addr).get_hash().del_elem(key);
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_getkeys(int local_scope_addr)
|
||||
int builtin_getkeys(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int hash_addr=in_builtin_find("hash");
|
||||
if(hash_addr<0 || !in_builtin_check(hash_addr,vm_hash))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_delete: \"hash\" has wrong type(must be hash).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int ret_addr=nasal_vm.gc_get(hash_addr).get_hash().get_keys();
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_import(int local_scope_addr)
|
||||
int builtin_import(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
// this function is used in preprocessing.
|
||||
// this function will return nothing when running.
|
||||
++error;
|
||||
std::cout<<">> [runtime] builtin_import: cannot use import when running.\n";
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_die(int local_scope_addr)
|
||||
int builtin_die(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int str_addr=in_builtin_find("str");
|
||||
if(str_addr<0 || !in_builtin_check(str_addr,vm_string))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_die: \"str\" has wrong type(must be string).\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
++error;
|
||||
builtin_die_state=true;
|
||||
std::cout<<">> [runtime] error: "<<nasal_vm.gc_get(str_addr).get_string()<<'\n';
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_nil);
|
||||
return ret_addr;
|
||||
}
|
||||
int nasal_runtime::builtin_type(int local_scope_addr)
|
||||
int builtin_type(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int value_addr=in_builtin_find("object");
|
||||
if(value_addr<0)
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_type: cannot find \"object\".\n";
|
||||
++error;
|
||||
return -1;
|
||||
}
|
||||
int type=nasal_vm.gc_get(value_addr).get_type();
|
||||
int ret_addr=nasal_vm.gc_alloc();
|
||||
nasal_vm.gc_get(ret_addr).set_type(vm_string);
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_string);
|
||||
switch(type)
|
||||
{
|
||||
case vm_nil: nasal_vm.gc_get(ret_addr).set_string("nil");break;
|
||||
@@ -786,4 +799,39 @@ int nasal_runtime::builtin_type(int local_scope_addr)
|
||||
}
|
||||
return ret_addr;
|
||||
}
|
||||
int builtin_substr(int local_scope_addr,nasal_virtual_machine& nasal_vm)
|
||||
{
|
||||
int str_addr=in_builtin_find("str");
|
||||
int begin_addr=in_builtin_find("begin");
|
||||
int length_addr=in_builtin_find("length");
|
||||
if(str_addr<0 || !in_builtin_check(str_addr,vm_string))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_substr: cannot find \"str\" or wrong type(must be string).\n";
|
||||
return -1;
|
||||
}
|
||||
if(begin_addr<0 || !in_builtin_check(begin_addr,vm_number))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_substr: cannot find \"begin\" or wrong type(must be number).\n";
|
||||
return -1;
|
||||
}
|
||||
if(length_addr<0 || !in_builtin_check(length_addr,vm_number))
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_substr: cannot find \"length\" or wrong type(must be number).\n";
|
||||
return -1;
|
||||
}
|
||||
std::string str=nasal_vm.gc_get(str_addr).get_string();
|
||||
int begin=(int)nasal_vm.gc_get(begin_addr).get_number();
|
||||
int len=(int)nasal_vm.gc_get(length_addr).get_number();
|
||||
if(begin>=str.length() || begin+len>=str.length())
|
||||
{
|
||||
std::cout<<">> [runtime] builtin_substr: index out of range.\n";
|
||||
return -1;
|
||||
}
|
||||
std::string tmp="";
|
||||
for(int i=begin;i<begin+len;++i)
|
||||
tmp+=str[i];
|
||||
int ret_addr=nasal_vm.gc_alloc(vm_string);
|
||||
nasal_vm.gc_get(ret_addr).set_string(tmp);
|
||||
return ret_addr;
|
||||
}
|
||||
#endif
|
||||
1466
nasal_bytecode_vm.h
Normal file
1466
nasal_bytecode_vm.h
Normal file
File diff suppressed because it is too large
Load Diff
1354
nasal_codegen.h
1354
nasal_codegen.h
File diff suppressed because it is too large
Load Diff
190
nasal_enum.h
190
nasal_enum.h
@@ -1,190 +0,0 @@
|
||||
#ifndef __NASAL_ENUM_H__
|
||||
#define __NASAL_ENUM_H__
|
||||
|
||||
/* token_type is used in lexer */
|
||||
enum token_type
|
||||
{
|
||||
tok_null=0,
|
||||
tok_number,tok_string,tok_identifier,
|
||||
tok_for,tok_forindex,tok_foreach,tok_while,
|
||||
tok_var,tok_func,tok_break,tok_continue,
|
||||
tok_return,tok_if,tok_elsif,tok_else,tok_nil,
|
||||
tok_left_curve,tok_right_curve,
|
||||
tok_left_bracket,tok_right_bracket,
|
||||
tok_left_brace,tok_right_brace,
|
||||
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_equal,
|
||||
tok_add_equal,tok_sub_equal,tok_mult_equal,tok_div_equal,tok_link_equal,
|
||||
tok_cmp_equal,tok_cmp_not_equal,tok_less_than,tok_greater_than,tok_less_equal,tok_greater_equal
|
||||
};
|
||||
|
||||
enum ast_node
|
||||
{
|
||||
ast_null=0,ast_root,ast_block,
|
||||
ast_nil,ast_number,ast_string,ast_identifier,ast_function,ast_hash,ast_vector,
|
||||
ast_hashmember,ast_call,ast_call_hash,ast_call_vec,ast_call_func,ast_subvec,
|
||||
ast_args,ast_default_arg,ast_dynamic_id,
|
||||
ast_and,ast_or,
|
||||
ast_equal,ast_add_equal,ast_sub_equal,ast_mult_equal,ast_div_equal,ast_link_equal,
|
||||
ast_cmp_equal,ast_cmp_not_equal,ast_less_than,ast_less_equal,ast_greater_than,ast_greater_equal,
|
||||
ast_add,ast_sub,ast_mult,ast_div,ast_link,
|
||||
ast_unary_sub,ast_unary_not,
|
||||
ast_trinocular,
|
||||
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_definition,ast_multi_assign,
|
||||
ast_continue,ast_break,ast_return
|
||||
};
|
||||
|
||||
std::string ast_str(int type)
|
||||
{
|
||||
std::string str;
|
||||
switch(type)
|
||||
{
|
||||
case ast_null: str="null";break;
|
||||
case ast_root: str="root";break;
|
||||
case ast_block: str="block";break;
|
||||
case ast_nil: str="nil";break;
|
||||
case ast_number: str="number";break;
|
||||
case ast_string: str="string";break;
|
||||
case ast_identifier: str="id";break;
|
||||
case ast_function: str="function";break;
|
||||
case ast_hash: str="hash";break;
|
||||
case ast_vector: str="vector";break;
|
||||
case ast_hashmember: str="hashmember";break;
|
||||
case ast_call: str="call";break;
|
||||
case ast_call_hash: str="call_hash";break;
|
||||
case ast_call_vec: str="call_vector";break;
|
||||
case ast_call_func: str="call_func";break;
|
||||
case ast_subvec: str="subvec";break;
|
||||
case ast_args: str="arguments";break;
|
||||
case ast_default_arg: str="default_arg";break;
|
||||
case ast_dynamic_id: str="dynamic_id";break;
|
||||
case ast_and: str="and";break;
|
||||
case ast_or: str="or";break;
|
||||
case ast_equal: str="=";break;
|
||||
case ast_add_equal: str="+=";break;
|
||||
case ast_sub_equal: str="-=";break;
|
||||
case ast_mult_equal: str="*=";break;
|
||||
case ast_div_equal: str="/=";break;
|
||||
case ast_link_equal: str="~=";break;
|
||||
case ast_cmp_equal: str="==";break;
|
||||
case ast_cmp_not_equal:str="!=";break;
|
||||
case ast_less_than: str="<";break;
|
||||
case ast_less_equal: str="<=";break;
|
||||
case ast_greater_than: str=">";break;
|
||||
case ast_greater_equal:str=">=";break;
|
||||
case ast_add: str="+";break;
|
||||
case ast_sub: str="-";break;
|
||||
case ast_mult: str="*";break;
|
||||
case ast_div: str="/";break;
|
||||
case ast_link: str="~";break;
|
||||
case ast_unary_sub: str="unary-";break;
|
||||
case ast_unary_not: str="unary!";break;
|
||||
case ast_trinocular: str="trinocular";break;
|
||||
case ast_for: str="for";break;
|
||||
case ast_forindex: str="forindex";break;
|
||||
case ast_foreach: str="foreach";break;
|
||||
case ast_while: str="while";break;
|
||||
case ast_new_iter: str="new_iterator";break;
|
||||
case ast_conditional: str="conditional";break;
|
||||
case ast_if: str="if";break;
|
||||
case ast_elsif: str="elsif";break;
|
||||
case ast_else: str="else";break;
|
||||
case ast_multi_id: str="multi_id";break;
|
||||
case ast_multi_scalar: str="multi_scalar";break;
|
||||
case ast_definition: str="definition";break;
|
||||
case ast_multi_assign: str="multi_assignment";break;
|
||||
case ast_continue: str="continue";break;
|
||||
case ast_break: str="break";break;
|
||||
case ast_return: str="return";break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
enum parse_error
|
||||
{
|
||||
unknown,
|
||||
error_token,
|
||||
error_expr,
|
||||
lack_left_curve,
|
||||
lack_right_curve,
|
||||
lack_left_bracket,
|
||||
lack_right_bracket,
|
||||
lack_left_brace,
|
||||
lack_right_brace,
|
||||
exprs_lack_rbrace,
|
||||
lack_semi,
|
||||
lack_comma,
|
||||
lack_colon,
|
||||
lack_equal,
|
||||
lack_scalar,
|
||||
lack_identifier,
|
||||
lack_calculation,
|
||||
lack_exprs,
|
||||
lack_token,
|
||||
lack_args,
|
||||
default_arg_not_end,
|
||||
dynamic_id_not_end,
|
||||
name_repetition,
|
||||
definition_use_call,
|
||||
multi_id_use_call,
|
||||
multi_assign_lack_val,
|
||||
lack_definition,
|
||||
lack_loop_iter,
|
||||
lack_func_content
|
||||
};
|
||||
|
||||
void error_info(int line,int error_type,std::string error_str="")
|
||||
{
|
||||
std::string detail;
|
||||
std::cout<<">> [parse] error_info: [line "<<line<<"] ";
|
||||
switch(error_type)
|
||||
{
|
||||
case unknown: std::cout<<"unknown error.\n"; break;
|
||||
case error_token: std::cout<<"error token \""+error_str+"\".\n"; break;
|
||||
case error_expr: std::cout<<"error expression \""+error_str+"\".\n"; break;
|
||||
case lack_left_curve: std::cout<<"expected \"(\".\n"; break;
|
||||
case lack_right_curve: std::cout<<"expected \")\".\n"; break;
|
||||
case lack_left_bracket: std::cout<<"expected \"[\".\n"; break;
|
||||
case lack_right_bracket: std::cout<<"expected \"]\".\n"; break;
|
||||
case lack_left_brace: std::cout<<"expected \"{\".\n"; break;
|
||||
case lack_right_brace: std::cout<<"expected \"}\".\n"; break;
|
||||
case exprs_lack_rbrace: std::cout<<"expected \"}\" with this line\'s \"{\".\n";break;
|
||||
case lack_semi: std::cout<<"expected \";\".\n"; break;
|
||||
case lack_comma: std::cout<<"expected \",\".\n"; break;
|
||||
case lack_colon: std::cout<<"expected \":\".\n"; break;
|
||||
case lack_equal: std::cout<<"expected \"=\".\n"; break;
|
||||
case lack_scalar: std::cout<<"expected scalar here.\n"; break;
|
||||
case lack_identifier: std::cout<<"expected identifier here.\n"; break;
|
||||
case lack_calculation: std::cout<<"expected arithmetic-expression here.\n"; break;
|
||||
case lack_exprs: std::cout<<"expected expression block here.\n"; break;
|
||||
case lack_token: std::cout<<"expected \""+error_str+"\" here.\n"; break;
|
||||
case lack_args: std::cout<<"expected arguments here.\n"; break;
|
||||
case default_arg_not_end: std::cout<<"default argument missing for parameter of "+error_str+".\n";break;
|
||||
case dynamic_id_not_end: std::cout<<"dynamic id must be the end of "+error_str+".\n";break;
|
||||
case name_repetition: std::cout<<"this identifier name has existed.\n";break;
|
||||
case definition_use_call: std::cout<<"should not use call_scalar in definition progress.\n";break;
|
||||
case multi_id_use_call: std::cout<<"should not use call_scalar in multi_id progress.\n";break;
|
||||
case multi_assign_lack_val:std::cout<<"multi-assignment lacks value list.\n";break;
|
||||
case lack_definition: std::cout<<"expected a definition expression here.\n";break;
|
||||
case lack_loop_iter: std::cout<<"expected an iterator to loop through.\n";break;
|
||||
case lack_func_content: std::cout<<"expected arguments or expression block here.\n";break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
enum runtime_scalar_type
|
||||
{
|
||||
vm_nil=0,
|
||||
vm_number,
|
||||
vm_string,
|
||||
vm_closure,
|
||||
vm_function,
|
||||
vm_vector,
|
||||
vm_hash
|
||||
};
|
||||
|
||||
#endif
|
||||
1396
nasal_gc.h
1396
nasal_gc.h
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@
|
||||
class nasal_import
|
||||
{
|
||||
private:
|
||||
nasal_resource import_src;
|
||||
nasal_lexer import_lex;
|
||||
nasal_parse import_par;
|
||||
nasal_ast import_ast;
|
||||
@@ -20,13 +19,12 @@ private:
|
||||
public:
|
||||
nasal_import();
|
||||
int get_error();
|
||||
void preprocessing(nasal_ast&);
|
||||
void link(nasal_ast&);
|
||||
nasal_ast& get_root();
|
||||
};
|
||||
|
||||
nasal_import::nasal_import()
|
||||
{
|
||||
import_src.clear();
|
||||
import_lex.clear();
|
||||
import_par.clear();
|
||||
import_ast.clear();
|
||||
@@ -43,7 +41,6 @@ void nasal_import::die(std::string filename,std::string error_stage)
|
||||
|
||||
void nasal_import::init()
|
||||
{
|
||||
import_src.clear();
|
||||
import_lex.clear();
|
||||
import_par.clear();
|
||||
return;
|
||||
@@ -112,12 +109,8 @@ nasal_ast nasal_import::file_import(nasal_ast& node)
|
||||
return tmp;
|
||||
|
||||
// start importing...
|
||||
if(!import_src.input_file(filename))
|
||||
{
|
||||
this->die(filename,"resource");
|
||||
return tmp;
|
||||
}
|
||||
import_lex.scanner(import_src.get_file());
|
||||
import_lex.openfile(filename);
|
||||
import_lex.scanner();
|
||||
if(import_lex.get_error())
|
||||
{
|
||||
this->die(filename,"lexer");
|
||||
@@ -160,7 +153,7 @@ nasal_ast nasal_import::load(nasal_ast& root)
|
||||
return new_root;
|
||||
}
|
||||
|
||||
void nasal_import::preprocessing(nasal_ast& root)
|
||||
void nasal_import::link(nasal_ast& root)
|
||||
{
|
||||
// initializing
|
||||
error=0;
|
||||
|
||||
214
nasal_lexer.h
214
nasal_lexer.h
@@ -1,26 +1,40 @@
|
||||
#ifndef __NASAL_LEXER_H__
|
||||
#define __NASAL_LEXER_H__
|
||||
|
||||
#define IS_IDENTIFIER_HEAD(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z'))
|
||||
#define IS_IDENTIFIER_BODY(c) ((c=='_')||('a'<=c && c<='z')||('A'<=c&&c<='Z')||('0'<=c&&c<='9'))
|
||||
#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_HEAD(c) (c=='\''||c=='\"')
|
||||
#define IS_STRING(c) (c=='\''||c=='\"'||c=='`')
|
||||
// single operators have only one character
|
||||
#define IS_SINGLE_OPRATOR(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_HEAD(c) (c=='#')
|
||||
#define IS_NOTE(c) (c=='#')
|
||||
|
||||
#ifndef TOKEN_TABLE_SIZE
|
||||
#define TOKEN_TABLE_SIZE 45
|
||||
struct token_table
|
||||
enum token_type
|
||||
{
|
||||
std::string str;
|
||||
tok_null=0,
|
||||
tok_number,tok_string,tok_identifier,
|
||||
tok_for,tok_forindex,tok_foreach,tok_while,
|
||||
tok_var,tok_func,tok_break,tok_continue,
|
||||
tok_return,tok_if,tok_elsif,tok_else,tok_nil,
|
||||
tok_left_curve,tok_right_curve,
|
||||
tok_left_bracket,tok_right_bracket,
|
||||
tok_left_brace,tok_right_brace,
|
||||
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_equal,
|
||||
tok_add_equal,tok_sub_equal,tok_mult_equal,tok_div_equal,tok_link_equal,
|
||||
tok_cmp_equal,tok_cmp_not_equal,tok_less_than,tok_less_equal,tok_greater_than,tok_greater_equal
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
const char* str;
|
||||
int tok_type;
|
||||
}tok_tbl[TOKEN_TABLE_SIZE]=
|
||||
}token_table[]=
|
||||
{
|
||||
{"for" ,tok_for },
|
||||
{"forindex",tok_forindex },
|
||||
@@ -64,11 +78,11 @@ struct token_table
|
||||
{"==" ,tok_cmp_equal },
|
||||
{"!=" ,tok_cmp_not_equal},
|
||||
{"<" ,tok_less_than },
|
||||
{"<=" ,tok_less_equal },
|
||||
{">" ,tok_greater_than },
|
||||
{"<=" ,tok_less_equal },
|
||||
{">=" ,tok_greater_equal},
|
||||
{NULL ,-1 }
|
||||
};
|
||||
#endif
|
||||
|
||||
struct token
|
||||
{
|
||||
@@ -81,14 +95,20 @@ 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;
|
||||
std::string identifier_gen(std::vector<char>&,int&,int&);
|
||||
void generate_number_error(int,std::string);
|
||||
std::string number_gen(std::vector<char>&,int&,int&);
|
||||
std::string string_gen(std::vector<char>&,int&,int&);
|
||||
std::string identifier_gen();
|
||||
std::string number_gen();
|
||||
std::string string_gen();
|
||||
public:
|
||||
void clear();
|
||||
void scanner(std::vector<char>&);
|
||||
void openfile(std::string);
|
||||
void die(std::string,int,int);
|
||||
void scanner();
|
||||
void print_token();
|
||||
int get_error();
|
||||
std::vector<token>& get_token_list();
|
||||
@@ -96,29 +116,59 @@ public:
|
||||
|
||||
void nasal_lexer::clear()
|
||||
{
|
||||
error=0;
|
||||
res_size=0;
|
||||
line=0;
|
||||
ptr=0;
|
||||
line_code="";
|
||||
res.clear();
|
||||
token_list.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::identifier_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
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();
|
||||
res_size=res.size();
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_lexer::die(std::string error_info,int line=-1,int column=-1)
|
||||
{
|
||||
++error;
|
||||
std::cout<<">> [lexer] line "<<line<<" column "<<column<<": "<<error_info<<"\n";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::identifier_gen()
|
||||
{
|
||||
int res_size=res.size();
|
||||
std::string token_str="";
|
||||
while(ptr<res_size && IS_IDENTIFIER_BODY(res[ptr]))
|
||||
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
|
||||
}
|
||||
|
||||
void nasal_lexer::generate_number_error(int line,std::string token_str)
|
||||
std::string nasal_lexer::number_gen()
|
||||
{
|
||||
++error;
|
||||
std::cout<<">> [lexer] line "<<line<<": \""<<token_str<<"\" is not a correct number.\n";
|
||||
return;
|
||||
}
|
||||
std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
{
|
||||
int res_size=res.size();
|
||||
bool scientific_notation=false;// numbers like 1e8 are scientific_notation
|
||||
std::string token_str="";
|
||||
// generate hex number
|
||||
@@ -128,9 +178,10 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
ptr+=2;
|
||||
while(ptr<res_size && IS_HEX_NUMBER(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
if(token_str=="0x")
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
return token_str;
|
||||
@@ -142,17 +193,16 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
ptr+=2;
|
||||
while(ptr<res_size && IS_OCT_NUMEBR(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
line_code+=token_str;
|
||||
if(token_str=="0o")
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
return token_str;
|
||||
}
|
||||
// generate dec number
|
||||
// dec number -> 0|[1~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
if(ptr<res_size && res[ptr]=='0')
|
||||
token_str+=res[ptr++];
|
||||
// dec number -> [0~9][0~9]*(.[0~9]*)(e|E(+|-)0|[1~9][0~9]*)
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
token_str+=res[ptr++];
|
||||
if(ptr<res_size && res[ptr]=='.')
|
||||
@@ -161,7 +211,8 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
// "xxxx." is not a correct number
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
line_code+=token_str;
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
while(ptr<res_size && IS_DIGIT(res[ptr]))
|
||||
@@ -169,7 +220,8 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
// "xxxx." is not a correct number
|
||||
if(token_str.back()=='.')
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
line_code+=token_str;
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
@@ -179,14 +231,16 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
// "xxxe" is not a correct number
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
line_code+=token_str;
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
if(ptr<res_size && (res[ptr]=='-' || res[ptr]=='+'))
|
||||
token_str+=res[ptr++];
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
line_code+=token_str;
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
if(ptr<res_size && res[ptr]=='0')
|
||||
@@ -196,25 +250,32 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
// "xxxe(-|+)" is not a correct number
|
||||
if(token_str.back()=='e' || token_str.back()=='E' || token_str.back()=='-' || token_str.back()=='+')
|
||||
{
|
||||
generate_number_error(line,token_str);
|
||||
line_code+=token_str;
|
||||
die("["+line_code+"_] incorrect number.",line,line_code.length());
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
line_code+=token_str;
|
||||
return token_str;
|
||||
}
|
||||
|
||||
std::string nasal_lexer::string_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
std::string nasal_lexer::string_gen()
|
||||
{
|
||||
int res_size=res.size();
|
||||
std::string token_str="";
|
||||
line_code+=res[ptr];
|
||||
char str_begin=res[ptr++];
|
||||
if(ptr>=res_size) return token_str;
|
||||
while(ptr<res_size && res[ptr]!=str_begin)
|
||||
{
|
||||
if(res[ptr]=='\n') ++line;
|
||||
if(res[ptr]=='\\' && ptr+1<res.size())
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr]=='\n')
|
||||
{
|
||||
line_code="";
|
||||
++line;
|
||||
}
|
||||
if(res[ptr]=='\\' && ptr+1<res_size)
|
||||
{
|
||||
++ptr;
|
||||
line_code+=res[ptr];
|
||||
switch(res[ptr])
|
||||
{
|
||||
case 'a':token_str.push_back('\a');break;
|
||||
@@ -238,40 +299,44 @@ std::string nasal_lexer::string_gen(std::vector<char>& res,int& ptr,int& line)
|
||||
}
|
||||
// check if this string ends with a " or '
|
||||
if(ptr>=res_size)
|
||||
{
|
||||
++error;
|
||||
std::cout<<">> [lexer] line "<<line<<": get EOF when generating string.\n";
|
||||
}
|
||||
die("["+line_code+"_] get EOF when generating string.",line,line_code.length());
|
||||
++ptr;
|
||||
return token_str;
|
||||
}
|
||||
|
||||
void nasal_lexer::scanner(std::vector<char>& res)
|
||||
void nasal_lexer::scanner()
|
||||
{
|
||||
error=0;
|
||||
token_list.clear();
|
||||
int line=1,ptr=0,res_size=res.size();
|
||||
line=1;
|
||||
ptr=0;
|
||||
line_code="";
|
||||
|
||||
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
|
||||
if(res[ptr]=='\n') ++line;
|
||||
line_code+=res[ptr];
|
||||
if(res[ptr]=='\n')
|
||||
{
|
||||
++line;
|
||||
line_code="";
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
if(ptr>=res_size) break;
|
||||
if(IS_IDENTIFIER_HEAD(res[ptr]))
|
||||
if(IS_IDENTIFIER(res[ptr]))
|
||||
{
|
||||
token_str=identifier_gen(res,ptr,line);
|
||||
token_str=identifier_gen();
|
||||
token new_token;
|
||||
new_token.line=line;
|
||||
new_token.str=token_str;
|
||||
new_token.type=0;
|
||||
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
|
||||
if(token_str==tok_tbl[i].str)
|
||||
for(int i=0;token_table[i].str;++i)
|
||||
if(token_str==token_table[i].str)
|
||||
{
|
||||
new_token.type=tok_tbl[i].tok_type;
|
||||
new_token.type=token_table[i].tok_type;
|
||||
break;
|
||||
}
|
||||
if(!new_token.type)
|
||||
@@ -280,16 +345,16 @@ void nasal_lexer::scanner(std::vector<char>& res)
|
||||
}
|
||||
else if(IS_DIGIT(res[ptr]))
|
||||
{
|
||||
token_str=number_gen(res,ptr,line);
|
||||
token_str=number_gen();
|
||||
token new_token;
|
||||
new_token.line=line;
|
||||
new_token.str=token_str;
|
||||
new_token.type=tok_number;
|
||||
token_list.push_back(new_token);
|
||||
}
|
||||
else if(IS_STRING_HEAD(res[ptr]))
|
||||
else if(IS_STRING(res[ptr]))
|
||||
{
|
||||
token_str=string_gen(res,ptr,line);
|
||||
token_str=string_gen();
|
||||
token new_token;
|
||||
new_token.line=line;
|
||||
new_token.type=tok_string;
|
||||
@@ -300,15 +365,19 @@ void nasal_lexer::scanner(std::vector<char>& res)
|
||||
{
|
||||
token_str="";
|
||||
token_str+=res[ptr];
|
||||
line_code+=res[ptr];
|
||||
token new_token;
|
||||
new_token.line=line;
|
||||
new_token.str=token_str;
|
||||
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
|
||||
if(token_str==tok_tbl[i].str)
|
||||
new_token.type=-1;
|
||||
for(int i=0;token_table[i].str;++i)
|
||||
if(token_str==token_table[i].str)
|
||||
{
|
||||
new_token.type=tok_tbl[i].tok_type;
|
||||
new_token.type=token_table[i].tok_type;
|
||||
break;
|
||||
}
|
||||
if(new_token.type<0)
|
||||
die("["+line_code+"_] incorrect operator.",line,line_code.length());
|
||||
token_list.push_back(new_token);
|
||||
++ptr;
|
||||
}
|
||||
@@ -324,13 +393,14 @@ void nasal_lexer::scanner(std::vector<char>& res)
|
||||
token_str=".";
|
||||
++ptr;
|
||||
}
|
||||
line_code+=token_str;
|
||||
token new_token;
|
||||
new_token.line=line;
|
||||
new_token.str=token_str;
|
||||
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
|
||||
if(token_str==tok_tbl[i].str)
|
||||
for(int i=0;token_table[i].str;++i)
|
||||
if(token_str==token_table[i].str)
|
||||
{
|
||||
new_token.type=tok_tbl[i].tok_type;
|
||||
new_token.type=token_table[i].tok_type;
|
||||
break;
|
||||
}
|
||||
token_list.push_back(new_token);
|
||||
@@ -338,26 +408,26 @@ void nasal_lexer::scanner(std::vector<char>& res)
|
||||
else if(IS_CALC_OPERATOR(res[ptr]))
|
||||
{
|
||||
// get calculation operator
|
||||
token_str="";
|
||||
token_str+=res[ptr];
|
||||
token_str=res[ptr];
|
||||
++ptr;
|
||||
if(ptr<res.size() && res[ptr]=='=')
|
||||
{
|
||||
token_str+=res[ptr];
|
||||
++ptr;
|
||||
}
|
||||
line_code+=token_str;
|
||||
token new_token;
|
||||
new_token.line=line;
|
||||
new_token.str=token_str;
|
||||
for(int i=0;i<TOKEN_TABLE_SIZE;++i)
|
||||
if(token_str==tok_tbl[i].str)
|
||||
for(int i=0;token_table[i].str;++i)
|
||||
if(token_str==token_table[i].str)
|
||||
{
|
||||
new_token.type=tok_tbl[i].tok_type;
|
||||
new_token.type=token_table[i].tok_type;
|
||||
break;
|
||||
}
|
||||
token_list.push_back(new_token);
|
||||
}
|
||||
else if(IS_NOTE_HEAD(res[ptr]))
|
||||
else if(IS_NOTE(res[ptr]))
|
||||
{
|
||||
// avoid note
|
||||
while(ptr<res_size && res[ptr]!='\n') ++ptr;
|
||||
@@ -366,8 +436,8 @@ void nasal_lexer::scanner(std::vector<char>& res)
|
||||
}
|
||||
else
|
||||
{
|
||||
++error;
|
||||
std::cout<<">> [lexer] line "<<line<<": unknown char "<<(int)res[ptr]<<'.'<<std::endl;
|
||||
line_code+=res[ptr];
|
||||
die("["+line_code+"_] unknown character.",line,line_code.length());
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
|
||||
258
nasal_misc.h
258
nasal_misc.h
@@ -1,258 +0,0 @@
|
||||
#ifndef __NASAL_MISC_H__
|
||||
#define __NASAL_MISC_H__
|
||||
|
||||
/*
|
||||
check_numerable_string:
|
||||
check if a string can be converted to a number
|
||||
|
||||
strings like these below is correct:
|
||||
'0.00012'
|
||||
'12314.234'
|
||||
'1234'
|
||||
'0xdeadbeef'
|
||||
'0xDEADBEEF'
|
||||
'0o71230'
|
||||
'1e23'
|
||||
'1E-123'
|
||||
'1.34E10'
|
||||
*/
|
||||
inline bool check_hex_string(std::string str,int len)
|
||||
{
|
||||
for(int i=2;i<len;++i)
|
||||
if(!(('0'<=str[i] && str[i]<='9') || ('a'<=str[i] && str[i]<='f') || ('A'<=str[i] && str[i]<='F')))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
inline bool check_oct_string(std::string str,int len)
|
||||
{
|
||||
for(int i=2;i<len;++i)
|
||||
if(str[i]<'0' || str[i]>'7')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
inline bool check_dec_string(std::string str,int len)
|
||||
{
|
||||
int i=0;
|
||||
// check integer part
|
||||
while('0'<=str[i] && str[i]<='9' && i<len) ++i;
|
||||
if(i==len) return true;
|
||||
if(str[i]!='e' && str[i]!='E' && str[i]!='.') return false;
|
||||
// check decimal part
|
||||
if(str[i]=='.')
|
||||
{
|
||||
++i;
|
||||
if(i==len) return false;
|
||||
while('0'<=str[i] && str[i]<='9' && i<len) ++i;
|
||||
}
|
||||
if(i==len) return true;
|
||||
if(str[i]!='e' && str[i]!='E') return false;
|
||||
// check scientific notation
|
||||
if(str[i]=='e' || str[i]=='E')
|
||||
{
|
||||
++i;
|
||||
if(i==len) return false;
|
||||
if(str[i]=='-' || str[i]=='+')
|
||||
{
|
||||
++i;
|
||||
if(i==len) return false;
|
||||
}
|
||||
for(;i<len;++i)
|
||||
if(str[i]<'0' || str[i]>'9')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_numerable_string(std::string str)
|
||||
{
|
||||
int len=str.length();
|
||||
if(!len) return false;
|
||||
if(str[0]=='-' || str[0]=='+')
|
||||
{
|
||||
if(len==1) return false;
|
||||
std::string tmp="";
|
||||
for(int i=1;i<len;++i)
|
||||
tmp+=str[i];
|
||||
str=tmp;
|
||||
--len;
|
||||
}
|
||||
if(len>2 && str[0]=='0' && str[1]=='x')
|
||||
return check_hex_string(str,len);
|
||||
else if(len>2 && str[0]=='0' && str[1]=='o')
|
||||
return check_oct_string(str,len);
|
||||
else if('0'<=str[0] && str[0]<='9')
|
||||
return check_dec_string(str,len);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
trans_string_to_number:
|
||||
convert string to number
|
||||
*/
|
||||
inline double hex_to_double(std::string str,int len)
|
||||
{
|
||||
double ret=0,num_pow=1;
|
||||
for(int i=len-1;i>1;--i)
|
||||
{
|
||||
if('0'<=str[i] && str[i]<='9')
|
||||
ret+=num_pow*(str[i]-'0');
|
||||
else if('a'<=str[i] && str[i]<='f')
|
||||
ret+=num_pow*(str[i]-'a'+10);
|
||||
else if('A'<=str[i] && str[i]<='F')
|
||||
ret+=num_pow*(str[i]-'A'+10);
|
||||
num_pow*=16;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
inline double oct_to_double(std::string str,int len)
|
||||
{
|
||||
double ret=0,num_pow=1;
|
||||
for(int i=len-1;i>1;--i)
|
||||
{
|
||||
ret+=num_pow*(str[i]-'0');
|
||||
num_pow*=8;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
inline double dec_to_double(std::string str,int len)
|
||||
{
|
||||
double ret=0;
|
||||
int i=0;
|
||||
while('0'<=str[i] && str[i]<='9' && i<len)
|
||||
{
|
||||
ret=ret*10+(str[i]-'0');
|
||||
++i;
|
||||
}
|
||||
if(i==len) return ret;
|
||||
if(str[i]=='.')
|
||||
{
|
||||
++i;
|
||||
double num_pow=0.1;
|
||||
while('0'<=str[i] && str[i]<='9' && i<len)
|
||||
{
|
||||
ret+=num_pow*(str[i]-'0');
|
||||
num_pow*=0.1;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
if(i==len) return ret;
|
||||
if(str[i]=='e' || str[i]=='E')
|
||||
{
|
||||
++i;
|
||||
bool is_negative=(str[i]=='-');
|
||||
if(str[i]=='-' || str[i]=='+') ++i;
|
||||
double num_pow=0;
|
||||
for(;i<len;++i) num_pow=num_pow*10+(str[i]-'0');
|
||||
num_pow=std::pow(10,is_negative?-num_pow:num_pow);
|
||||
ret*=num_pow;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
double trans_string_to_number(std::string str)
|
||||
{
|
||||
bool is_negative=false;
|
||||
int len=str.length();
|
||||
double ret_num=0;
|
||||
if(!len) return 0;
|
||||
if(str[0]=='-' || str[0]=='+')
|
||||
{
|
||||
is_negative=(str[0]=='-');
|
||||
std::string tmp="";
|
||||
for(int i=1;i<len;++i)
|
||||
tmp.push_back(str[i]);
|
||||
str=tmp;
|
||||
--len;
|
||||
}
|
||||
if(len>2 && str[0]=='0' && str[1]=='x')
|
||||
ret_num=hex_to_double(str,len);
|
||||
else if(len>2 && str[0]=='0' && str[1]=='o')
|
||||
ret_num=oct_to_double(str,len);
|
||||
else if('0'<=str[0] && str[0]<='9')
|
||||
ret_num=dec_to_double(str,len);
|
||||
return is_negative?-ret_num:ret_num;
|
||||
}
|
||||
|
||||
/*
|
||||
trans_number_to_string:
|
||||
convert number to string
|
||||
*/
|
||||
std::string trans_number_to_string(double number)
|
||||
{
|
||||
std::string trans_num_string="";
|
||||
if(number<0)
|
||||
{
|
||||
trans_num_string+='-';
|
||||
number=-number;
|
||||
}
|
||||
if(number==0)
|
||||
return "0";
|
||||
double integer_bit=1;
|
||||
while(number>=integer_bit)
|
||||
integer_bit*=10;
|
||||
integer_bit/=10;
|
||||
if(integer_bit==0.1)
|
||||
trans_num_string+='0';
|
||||
while(integer_bit!=0.1)
|
||||
{
|
||||
trans_num_string+=(char)('0'+(int(number/integer_bit)));
|
||||
number-=(double)(int(number/integer_bit))*integer_bit;
|
||||
integer_bit/=10;
|
||||
}
|
||||
if(number!=0)
|
||||
trans_num_string+='.';
|
||||
while(number!=0)
|
||||
{
|
||||
trans_num_string+=(char)('0'+int(number*10));
|
||||
number*=10;
|
||||
number-=(double)(int(number));
|
||||
}
|
||||
return trans_num_string;
|
||||
}
|
||||
|
||||
/*
|
||||
prt_hex:
|
||||
transform int to hex format and print it out (std::cout)
|
||||
*/
|
||||
void prt_hex(const int ptr)
|
||||
{
|
||||
char hex[9];
|
||||
hex[8]=0;
|
||||
int tmp_plc=ptr;
|
||||
if(tmp_plc<0)
|
||||
{
|
||||
tmp_plc=-tmp_plc;
|
||||
std::cout<<"-0x";
|
||||
}
|
||||
else
|
||||
std::cout<<"0x";
|
||||
/*
|
||||
int: 00000000 00000000 00000000 00000000
|
||||
int: 0x00 00 00 00
|
||||
example:
|
||||
a=0x13 57 9b df
|
||||
a=00010011 01010111 10011011 11011111
|
||||
a & 0x00 00 00 0f:
|
||||
00010011 01010111 10011011 11011111
|
||||
and 00000000 00000000 00000000 00001111
|
||||
---------------------------------------
|
||||
00000000 00000000 00000000 00001111
|
||||
a>>=4:
|
||||
00000001 00110101 01111001 10111101
|
||||
a & 0x00 00 00 0f
|
||||
00000001 00110101 01111001 10111101
|
||||
and 00000000 00000000 00000000 00001111
|
||||
---------------------------------------
|
||||
00000000 00000000 00000000 00001101
|
||||
then convert 0~15 to 0~9 a~f
|
||||
*/
|
||||
for(int j=7;j>=0;--j)
|
||||
{
|
||||
int tmp=(tmp_plc & 0x0000000f);
|
||||
hex[j]=tmp<10? (char)('0'+tmp):(char)('a'+tmp-10);
|
||||
tmp_plc>>=4;
|
||||
}
|
||||
std::cout<<hex;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
1042
nasal_parse.h
1042
nasal_parse.h
File diff suppressed because it is too large
Load Diff
@@ -1,75 +0,0 @@
|
||||
#ifndef __NASAL_RESOURCE_H__
|
||||
#define __NASAL_RESOURCE_H__
|
||||
|
||||
class nasal_resource
|
||||
{
|
||||
private:
|
||||
std::vector<char> res;
|
||||
public:
|
||||
bool input_file(std::string);
|
||||
void clear();
|
||||
void print_file();
|
||||
std::vector<char>& get_file();
|
||||
};
|
||||
|
||||
bool nasal_resource::input_file(std::string filename)
|
||||
{
|
||||
res.clear();
|
||||
std::ifstream fin(filename,std::ios::binary);
|
||||
if(fin.fail())
|
||||
{
|
||||
std::cout<<">> [resource] cannot open file \""<<filename<<"\".\n";
|
||||
fin.close();
|
||||
return false;
|
||||
}
|
||||
while(!fin.eof())
|
||||
{
|
||||
char c=fin.get();
|
||||
if(fin.eof())
|
||||
break;
|
||||
res.push_back(c);
|
||||
}
|
||||
fin.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void nasal_resource::clear()
|
||||
{
|
||||
res.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
void nasal_resource::print_file()
|
||||
{
|
||||
int size=res.size(),line=1;
|
||||
std::cout<<line<<"\t";
|
||||
std::string unicode_str="";
|
||||
for(int i=0;i<size;++i)
|
||||
{
|
||||
if(res[i]>=0 && unicode_str.length())
|
||||
{
|
||||
std::cout<<unicode_str;
|
||||
unicode_str="";
|
||||
}
|
||||
if(32<=res[i])
|
||||
std::cout<<res[i];
|
||||
else if(res[i]<0)
|
||||
unicode_str+=res[i];
|
||||
else
|
||||
std::cout<<" ";
|
||||
if(res[i]=='\n')
|
||||
{
|
||||
++line;
|
||||
std::cout<<std::endl<<line<<"\t";
|
||||
}
|
||||
}
|
||||
std::cout<<(unicode_str.length()?unicode_str:"")<<'\n';
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<char>& nasal_resource::get_file()
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
1401
nasal_runtime.h
1401
nasal_runtime.h
File diff suppressed because it is too large
Load Diff
96
test/NasNeuron.nas
Normal file
96
test/NasNeuron.nas
Normal file
@@ -0,0 +1,96 @@
|
||||
# NasNeuron lib written by ValKmjolnir
|
||||
|
||||
# Basic Class NasMatrix
|
||||
# NasMatGen : generate a new matrix
|
||||
# NasMatAdd : add two matrixes
|
||||
# NasMatSub : sub two matrixes
|
||||
# NasMatMul : multiply two matrix
|
||||
# NasMatTrans: transpose a matrix
|
||||
# NasMatPrt : print a matrix
|
||||
var NasMatrix=
|
||||
{
|
||||
NasMatGen:func(row,col)
|
||||
{
|
||||
var GenMat={Row:row,Col:col,Elem:[]};
|
||||
for(var i=0;i<row;i+=1)
|
||||
{
|
||||
var TmpVec=[];
|
||||
for(var j=0;j<col;j+=1)
|
||||
append(TmpVec,0);
|
||||
append(GenMat.Elem,TmpVec);
|
||||
}
|
||||
return GenMat;
|
||||
},
|
||||
NasMatAdd:func(mat1,mat2)
|
||||
{
|
||||
var ResultMat=nil;
|
||||
if(mat1.Row==mat2.Row and mat1.Col==mat2.Col)
|
||||
{
|
||||
ResultMat=me.NasMatGen(mat1.Row,mat1.Col);
|
||||
for(var i=0;i<ResultMat.Row;i+=1)
|
||||
for(var j=0;j<ResultMat.Col;j+=1)
|
||||
ResultMat.Elem[i][j]=mat1.Elem[i][j]+mat2.Elem[i][j];
|
||||
}
|
||||
else
|
||||
print("NasNeuron: Mat1 and Mat2 have different rows and cols.");
|
||||
return ResultMat;
|
||||
},
|
||||
NasMatSub:func(mat1,mat2)
|
||||
{
|
||||
var ResultMat=nil;
|
||||
if(mat1.Row==mat2.Row and mat1.Col==mat2.Col)
|
||||
{
|
||||
ResultMat=me.NasMatGen(mat1.Row,mat1.Col);
|
||||
for(var i=0;i<ResultMat.Row;i+=1)
|
||||
for(var j=0;j<ResultMat.Col;j+=1)
|
||||
ResultMat.Elem[i][j]=mat1.Elem[i][j]-mat2.Elem[i][j];
|
||||
}
|
||||
else
|
||||
print("NasNeuron: Mat1 and Mat2 have different rows and cols.");
|
||||
return ResultMat;
|
||||
},
|
||||
NasMatMul:func(mat1,mat2)
|
||||
{
|
||||
var ResultMat=nil;
|
||||
if(mat1.Col==mat2.Row)
|
||||
{
|
||||
ResultMat=me.NasMatGen(mat1.Row,mat2.Col);
|
||||
for(var i=0;i<ResultMat.Row;i+=1)
|
||||
for(var j=0;j<ResultMat.Col;j+=1)
|
||||
{
|
||||
var sum=0;
|
||||
for(var k=0;k<mat1.Col;k+=1)
|
||||
sum+=mat1.Elem[i][k]*mat2.Elem[k][j];
|
||||
ResultMat.Elem[i][j]=sum;
|
||||
}
|
||||
}
|
||||
else
|
||||
print("NasNeuron: Mat1's Col is different from Mat2's Row.");
|
||||
return ResultMat;
|
||||
},
|
||||
NasMatTrans:func(mat)
|
||||
{
|
||||
var ResultMat=nil;
|
||||
ResultMat=me.NasMatGen(mat.Col,mat.Row);
|
||||
for(var i=0;i<ResultMat.Row;i+=1)
|
||||
for(var j=0;j<ResultMat.Col;j+=1)
|
||||
ResultMat.Elem[i][j]=mat.Elem[j][i];
|
||||
return ResultMat;
|
||||
},
|
||||
NasMatPrt:func(mat)
|
||||
{
|
||||
for(var i=0;i<mat.Row;i+=1)
|
||||
{
|
||||
for(var j=0;j<mat.Col;j+=1)
|
||||
print(mat.Elem[i][j],' ');
|
||||
print('\n');
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
};
|
||||
|
||||
NasMatrix.NasMatPrt(
|
||||
NasMatrix.NasMatGen(
|
||||
10,100
|
||||
)
|
||||
);
|
||||
65
test/bfs.nas
Normal file
65
test/bfs.nas
Normal file
@@ -0,0 +1,65 @@
|
||||
import("lib.nas");
|
||||
import("queue.nas");
|
||||
|
||||
rand(time(0));
|
||||
|
||||
var map=[];
|
||||
for(var i=0;i<10;i+=1)
|
||||
{
|
||||
append(map,[]);
|
||||
for(var j=0;j<10;j+=1)
|
||||
append(map[i],(rand()>0.7));
|
||||
}
|
||||
|
||||
var prt=func()
|
||||
{
|
||||
var s="";
|
||||
for(var i=0;i<10;i+=1)
|
||||
{
|
||||
for(var j=0;j<10;j+=1)
|
||||
s~=map[i][j];
|
||||
s~='\n';
|
||||
}
|
||||
print(s);
|
||||
}
|
||||
|
||||
var bfs=func(begin,end)
|
||||
{
|
||||
var move=[[1,0],[0,1],[-1,0],[0,-1]];
|
||||
var queue=new_queue();
|
||||
queue_push(queue,begin);
|
||||
map[begin[0]][begin[1]]=3;
|
||||
while(!queue_empty(queue))
|
||||
{
|
||||
var vertex=queue_front(queue);
|
||||
queue_pop(queue);
|
||||
foreach(var i;move)
|
||||
{
|
||||
var x=vertex[0]+i[0];
|
||||
var y=vertex[1]+i[1];
|
||||
if(x==end[0] and y==end[1])
|
||||
{
|
||||
map[x][y]='*';
|
||||
return;
|
||||
}
|
||||
if(0<=x and x<10 and 0<=y and y<10 and map[x][y]==0)
|
||||
{
|
||||
queue_push(queue,[x,y]);
|
||||
map[x][y]=3;
|
||||
}
|
||||
}
|
||||
prt();
|
||||
}
|
||||
print("cannot reach.");
|
||||
return;
|
||||
}
|
||||
|
||||
prt();
|
||||
var x=num(input());
|
||||
var y=num(input());
|
||||
var begin=[x,y];
|
||||
x=num(input());
|
||||
y=num(input());
|
||||
var end=[x,y];
|
||||
bfs(begin,end);
|
||||
prt();
|
||||
29
test/choice.nas
Normal file
29
test/choice.nas
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
var condition_true=1;
|
||||
var condition_false=0;
|
||||
if(condition_true)
|
||||
{
|
||||
var a=1;
|
||||
}
|
||||
else if(!condition_false)
|
||||
{
|
||||
var b=1;
|
||||
}
|
||||
elsif(!condition_true and condition_false)
|
||||
{
|
||||
print("impossible");
|
||||
}
|
||||
else
|
||||
{
|
||||
var c=1;
|
||||
var d=1;
|
||||
}
|
||||
|
||||
if(condition_true)
|
||||
var a=1;
|
||||
else if(!condition_false)
|
||||
var b=1;
|
||||
elsif(!condition_true and condition_false)
|
||||
print("impossible");
|
||||
else
|
||||
var c=1;
|
||||
2044
test/efb.nas
Normal file
2044
test/efb.nas
Normal file
File diff suppressed because it is too large
Load Diff
210
test/final.nas
Normal file
210
test/final.nas
Normal file
@@ -0,0 +1,210 @@
|
||||
var smartScreen = canvas.new({
|
||||
"name": "smartScreen", # The name is optional but allow for easier identification
|
||||
"size": [2048, 2048], # Size of the underlying texture (should be a power of 2, required) [Resolution]
|
||||
"view": [768, 768], # Virtual resolution (Defines the coordinate system of the canvas [Dimensions]
|
||||
# which will be stretched the size of the texture, required)
|
||||
"mipmapping": 1 # Enable mipmapping (optional)
|
||||
});
|
||||
|
||||
smartScreen.addPlacement({"node": "screen", "texture": "screen.jpeg"});
|
||||
var group = smartScreen.createGroup();
|
||||
|
||||
# Create a text element and set some values
|
||||
var text = group.createChild("text", "optional-id-for element")
|
||||
.setTranslation(10, 20) # The origin is in the top left corner
|
||||
.setAlignment("left-center") # All values from osgText are supported (see $FG_ROOT/Docs/README.osgtext)
|
||||
.setFont("LiberationFonts/LiberationSans-Regular.ttf") # Fonts are loaded either from $AIRCRAFT_DIR/Fonts or $FG_ROOT/Fonts
|
||||
.setFontSize(14, 1.2) # Set fontsize and optionally character aspect ratio
|
||||
.setColor(1,0,0) # Text color
|
||||
.setText("This is a text element");
|
||||
text.hide();
|
||||
text.setText("SELF TEST NORMAL").show();
|
||||
|
||||
|
||||
|
||||
var ui_root = smartScreen.createGroup();
|
||||
var vbox = canvas.VBoxLayout.new();
|
||||
smartScreen.setLayout(vbox);
|
||||
|
||||
|
||||
var button_onl = canvas.gui.widgets.Button.new(ui_root, canvas.style, {}).setText("Online OSM").listen("clicked", func showOnlineMap());
|
||||
var button_offl = canvas.gui.widgets.Button.new(ui_root, canvas.style, {}).setText("Offline OSM").listen("clicked", func showOfflineMap());
|
||||
button_onl.setSizeHint([32, 128]);
|
||||
button_offl.setSizeHint([32, 128]);
|
||||
|
||||
var label = canvas.gui.widgets.Label.new(ui_root, canvas.style, {});
|
||||
|
||||
var button_box = canvas.HBoxLayout.new();
|
||||
button_box.addItem(button_onl);
|
||||
button_box.addItem(button_offl);
|
||||
button_box.addItem(label);
|
||||
button_box.addStretch(1);
|
||||
|
||||
vbox.addItem(button_box);
|
||||
vbox.addStretch(1);
|
||||
|
||||
|
||||
var showOnlineMap = func(){
|
||||
TestMap.show();
|
||||
g.hide();
|
||||
label.setText("Online Mode");
|
||||
}
|
||||
|
||||
|
||||
var showOfflineMap = func(){
|
||||
TestMap.hide();
|
||||
g.show();
|
||||
label.setText("Offline Mode");
|
||||
}
|
||||
|
||||
|
||||
# Online Map using MapStructure
|
||||
var TestMap = smartScreen.createGroup().createChild("map");
|
||||
TestMap.setTranslation(smartScreen.get("view[0]")/2,smartScreen.get("view[1]")/2);
|
||||
|
||||
|
||||
var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
|
||||
var source = ctrl_ns.SOURCES["map-dialog"];
|
||||
if (source == nil) {
|
||||
# TODO: amend
|
||||
var source = ctrl_ns.SOURCES["map-dialog"] = {
|
||||
getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),# ? ? ?
|
||||
getAltitude: func getprop('/position/altitude-ft'),
|
||||
getHeading: func {
|
||||
if (me.aircraft_heading)
|
||||
getprop('/orientation/heading-deg');
|
||||
else
|
||||
0;
|
||||
},
|
||||
aircraft_heading: 1,
|
||||
};
|
||||
}
|
||||
setlistener("/sim/gui/dialogs/map-canvas/aircraft-heading-up", func(n){source.aircraft_heading = n.getBoolValue();}, 1);
|
||||
TestMap.setController("Aircraft position", "map-dialog");
|
||||
TestMap.setRange(1);
|
||||
|
||||
var r = func(name,vis=1,zindex=nil){return caller(0)[0];};
|
||||
# TODO: we'll need some z-indexing here, right now it's just random
|
||||
|
||||
foreach(var type; [r('APS')] ){
|
||||
TestMap.addLayer(factory: canvas.SymbolLayer, type_arg: type.name, visible: type.vis, priority: 2);
|
||||
}
|
||||
|
||||
foreach(var type; [ r('OSM')]) {
|
||||
TestMap.addLayer(factory: canvas.OverlayLayer,
|
||||
type_arg: type.name,
|
||||
visible: type.vis,
|
||||
priority: 1);
|
||||
}
|
||||
|
||||
|
||||
TestMap.hide();
|
||||
|
||||
# Offline map
|
||||
|
||||
var g = smartScreen.createGroup();
|
||||
var zoom = 15;
|
||||
var type = "intl";
|
||||
var tile_size = 256;
|
||||
|
||||
|
||||
var changeZoom = func(d)
|
||||
{
|
||||
zoom = math.max(2, math.min(19, zoom + d));
|
||||
updateTiles();
|
||||
}
|
||||
|
||||
# http://polymaps.org/docs/
|
||||
# https://github.com/simplegeo/polymaps
|
||||
# https://github.com/Leaflet/Leaflet
|
||||
|
||||
var maps_base = getprop("/sim/fg-home") ~ '/cache/maps';
|
||||
|
||||
var makePath =
|
||||
string.compileTemplate(maps_base ~ '/osm-{type}/{z}/{x}/{y}.jpg');
|
||||
var num_tiles = [4, 4];
|
||||
|
||||
var center_tile_offset = [(num_tiles[0]-1)/2, (num_tiles[1]-1)/ 2];
|
||||
|
||||
# simple aircraft icon at current position/center of the map
|
||||
g.createChild("path")
|
||||
.moveTo( tile_size*center_tile_offset[0]-10, tile_size*center_tile_offset[1])
|
||||
.horiz(20)
|
||||
.move(-10,-10)
|
||||
.vert(20)
|
||||
.set("stroke", "red")
|
||||
.set("stroke-width", 2)
|
||||
.set("z-index", 1);
|
||||
|
||||
# initialize the map by setting up
|
||||
# a grid of raster images
|
||||
|
||||
var tiles = setsize([], num_tiles[0]);
|
||||
for(var x=0; x<num_tiles[0]; x+=1)
|
||||
{
|
||||
tiles[x] = setsize([], num_tiles[1]);
|
||||
for(var y=0; y<num_tiles[1]; y+=1)
|
||||
tiles[x][y] = g.createChild("image", "map-tile");
|
||||
}
|
||||
|
||||
var last_tile = [-1,-1];
|
||||
var last_type = type;
|
||||
|
||||
# this is the callback that will be regularly called by the timer
|
||||
# to update the map
|
||||
var updateTiles = func()
|
||||
{
|
||||
# get current position
|
||||
var lat = getprop('/position/latitude-deg');
|
||||
var lon = getprop('/position/longitude-deg');
|
||||
|
||||
var n = math.pow(2, zoom);
|
||||
var offset = [n*((lon+180)/360)-center_tile_offset[0], (1-math.ln(math.tan(lat*math.pi/180)+1/math.cos(lat*math.pi/180))/math.pi)/2*n-center_tile_offset[1]];
|
||||
var tile_index = [int(offset[0]), int(offset[1])];
|
||||
|
||||
var ox = tile_index[0] - offset[0];
|
||||
var oy = tile_index[1] - offset[1];
|
||||
|
||||
for(var x = 0; x < num_tiles[0]; x += 1)
|
||||
for(var y = 0; y < num_tiles[1]; y += 1)
|
||||
tiles[x][y].setTranslation(int((ox + x) * tile_size + 0.5), int((oy + y) * tile_size + 0.5));
|
||||
|
||||
if( tile_index[0] != last_tile[0]
|
||||
or tile_index[1] != last_tile[1]
|
||||
or type != last_type )
|
||||
{
|
||||
for(var x = 0; x < num_tiles[0]; x += 1)
|
||||
for(var y = 0; y < num_tiles[1]; y += 1)
|
||||
{
|
||||
var pos = {
|
||||
z: zoom,
|
||||
x: int(offset[0] + x),
|
||||
y: int(offset[1] + y),
|
||||
type: type
|
||||
};
|
||||
|
||||
(func {
|
||||
var img_path = makePath(pos);
|
||||
var tile = tiles[x][y];
|
||||
print('loading ' ~ img_path);
|
||||
tile.set("src", img_path);
|
||||
})();
|
||||
# lambda
|
||||
}
|
||||
|
||||
last_tile = tile_index;
|
||||
last_type = type;
|
||||
}
|
||||
};
|
||||
|
||||
# set up a timer that will invoke updateTiles at 2-second intervals
|
||||
var update_timer = maketimer(2, updateTiles);
|
||||
# actually start the timer
|
||||
update_timer.start();
|
||||
|
||||
# set up default zoom level
|
||||
changeZoom(0);
|
||||
|
||||
#g.hide();
|
||||
|
||||
|
||||
643
test/final2.nas
Normal file
643
test/final2.nas
Normal file
@@ -0,0 +1,643 @@
|
||||
###############################################################################
|
||||
##
|
||||
## Nasal module for dual control over the multiplayer network.
|
||||
##
|
||||
## Copyright (C) 2007 - 2010 Anders Gidenstam (anders(at)gidenstam.org)
|
||||
## This file is licensed under the GPL license version 2 or later.
|
||||
##
|
||||
###############################################################################
|
||||
## MP properties
|
||||
var lat_mpp = "position/latitude-deg";
|
||||
var lon_mpp = "position/longitude-deg";
|
||||
var alt_mpp = "position/altitude-ft";
|
||||
var heading_mpp = "orientation/true-heading-deg";
|
||||
var pitch_mpp = "orientation/pitch-deg";
|
||||
var roll_mpp = "orientation/roll-deg";
|
||||
|
||||
# Import components from the mp_broadcast module.
|
||||
var Binary = mp_broadcast.Binary;
|
||||
var MessageChannel = mp_broadcast.MessageChannel;
|
||||
|
||||
###############################################################################
|
||||
# Utility classes
|
||||
|
||||
############################################################
|
||||
# Translate a property into another.
|
||||
# Factor and offsets are only used for numeric values.
|
||||
# src - source : property node
|
||||
# dest - destination : property node
|
||||
# factor - : double
|
||||
# offset - : double
|
||||
var Translator = {};
|
||||
Translator.new = func (src = nil, dest = nil, factor = 1, offset = 0) {
|
||||
var obj = { parents : [Translator],
|
||||
src : src,
|
||||
dest : dest,
|
||||
factor : factor,
|
||||
offset : offset };
|
||||
if (obj.src == nil or obj.dest == nil) {
|
||||
print("Translator[");
|
||||
print(" ", debug.string(obj.src));
|
||||
print(" ", debug.string(obj.dest));
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
Translator.update = func () {
|
||||
var v = me.src.getValue();
|
||||
if (is_num(v)) {
|
||||
me.dest.setValue(me.factor * v + me.offset);
|
||||
} else {
|
||||
if (typeof(v) == "scalar")
|
||||
me.dest.setValue(v);
|
||||
}
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Detects flanks on two insignals encoded in a property.
|
||||
# - positive signal up/down flank
|
||||
# - negative signal up/down flank
|
||||
# n - source : property node
|
||||
# on_positive_flank - action : func (v)
|
||||
# on_negative_flank - action : func (v)
|
||||
var EdgeTrigger = {};
|
||||
EdgeTrigger.new = func (n, on_positive_flank, on_negative_flank) {
|
||||
var obj = { parents : [EdgeTrigger],
|
||||
old : 0,
|
||||
node : n,
|
||||
pos_flank : on_positive_flank,
|
||||
neg_flank : on_negative_flank };
|
||||
if (obj.node == nil) {
|
||||
print("EdgeTrigger[");
|
||||
print(" ", debug.string(obj.node));
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
EdgeTrigger.update = func {
|
||||
# NOTE: float MP properties get interpolated.
|
||||
# This detector relies on that steady state is reached between
|
||||
# flanks.
|
||||
var val = me.node.getValue();
|
||||
if (!is_num(val)) return;
|
||||
if (me.old == 1) {
|
||||
if (val < me.old) {
|
||||
me.pos_flank(0);
|
||||
}
|
||||
} elsif (me.old == 0) {
|
||||
if (val > me.old) {
|
||||
me.pos_flank(1);
|
||||
} elsif (val < me.old) {
|
||||
me.neg_flank(1);
|
||||
}
|
||||
} elsif (me.old == -1) {
|
||||
if (val > me.old) {
|
||||
me.neg_flank(0);
|
||||
}
|
||||
}
|
||||
me.old = val;
|
||||
}
|
||||
|
||||
############################################################
|
||||
# StableTrigger: Triggers an action when a MPP property
|
||||
# becomes stable (i.e. doesn't change for
|
||||
# MIN_STABLE seconds).
|
||||
# src - MP prop : property node
|
||||
# action - action to take when the value becomes stable : [func(v)]
|
||||
# An action is triggered when value has stabilized.
|
||||
var StableTrigger = {};
|
||||
StableTrigger.new = func (src, action) {
|
||||
var obj = { parents : [StableTrigger],
|
||||
src : src,
|
||||
action : action,
|
||||
old : 0,
|
||||
stable_since : 0,
|
||||
wait : 0,
|
||||
MIN_STABLE : 0.01 };
|
||||
# Error checking.
|
||||
var bad = (obj.src == nil) or (action = nil);
|
||||
|
||||
if (bad) {
|
||||
print("StableTrigger[");
|
||||
print(" ", debug.string(obj.src));
|
||||
print(" ", debug.string(obj.action));
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
StableTrigger.update = func () {
|
||||
var v = me.src.getValue();
|
||||
if (!is_num(v)) return;
|
||||
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
|
||||
|
||||
if ((me.old == v) and
|
||||
((t - me.stable_since) > me.MIN_STABLE) and (me.wait == 1)) {
|
||||
# Trigger action.
|
||||
me.action(v);
|
||||
|
||||
me.wait = 0;
|
||||
} elsif (me.old == v) {
|
||||
# Wait. This is either before the signal is stable or after the action.
|
||||
} else {
|
||||
me.stable_since = t;
|
||||
me.wait = 1;
|
||||
me.old = me.src.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Selects the most recent value of two properties.
|
||||
# src1 - : property node
|
||||
# src2 - : property node
|
||||
# dest - : property node
|
||||
# threshold - : double
|
||||
var MostRecentSelector = {};
|
||||
MostRecentSelector.new = func (src1, src2, dest, threshold) {
|
||||
var obj = { parents : [MostRecentSelector],
|
||||
old1 : 0,
|
||||
old2 : 0,
|
||||
src1 : src1,
|
||||
src2 : src2,
|
||||
dest : dest,
|
||||
thres : threshold };
|
||||
if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) {
|
||||
print("MostRecentSelector[");
|
||||
print(" ", debug.string(obj.src1));
|
||||
print(" ", debug.string(obj.src2));
|
||||
print(" ", debug.string(obj.dest));
|
||||
print("]");
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
MostRecentSelector.update = func {
|
||||
var v1 = me.src1.getValue();
|
||||
var v2 = me.src2.getValue();
|
||||
if (!is_num(v1) and !is_num(v2)) return;
|
||||
elsif (!is_num(v1)) me.dest.setValue(v2);
|
||||
elsif (!is_num(v2)) me.dest.setValue(v1);
|
||||
else {
|
||||
if (abs (v2 - me.old2) > me.thres) {
|
||||
me.old2 = v2;
|
||||
me.dest.setValue(me.old2);
|
||||
}
|
||||
if (abs (v1 - me.old1) > me.thres) {
|
||||
me.old1 = v1;
|
||||
me.dest.setValue(me.old1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Adds two input properties.
|
||||
# src1 - : property node
|
||||
# src2 - : property node
|
||||
# dest - : property node
|
||||
var Adder = {};
|
||||
Adder.new = func (src1, src2, dest) {
|
||||
var obj = { parents : [DeltaAccumulator],
|
||||
src1 : src1,
|
||||
src2 : src2,
|
||||
dest : dest };
|
||||
if (obj.src1 == nil or obj.src2 == nil or obj.dest == nil) {
|
||||
print("Adder[");
|
||||
print(" ", debug.string(obj.src1));
|
||||
print(" ", debug.string(obj.src2));
|
||||
print(" ", debug.string(obj.dest));
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
Adder.update = func () {
|
||||
var v1 = me.src1.getValue();
|
||||
var v2 = me.src2.getValue();
|
||||
if (!is_num(v1) or !is_num(v2)) return;
|
||||
me.dest.setValue(v1 + v2);
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Adds the delta of src to dest.
|
||||
# src - : property node
|
||||
# dest - : property node
|
||||
var DeltaAdder = {};
|
||||
DeltaAdder.new = func (src, dest) {
|
||||
var obj = { parents : [DeltaAdder],
|
||||
old : 0,
|
||||
src : src,
|
||||
dest : dest };
|
||||
if (obj.src == nil or obj.dest == nil) {
|
||||
print("DeltaAdder[", debug.string(obj.src), ", ",
|
||||
debug.string(obj.dest), "]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
DeltaAdder.update = func () {
|
||||
var v = me.src.getValue();
|
||||
if (!is_num(v)) return;
|
||||
me.dest.setValue((v - me.old) + me.dest.getValue());
|
||||
me.old = v;
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Switch encoder: Encodes upto 32 boolean properties in one
|
||||
# int property.
|
||||
# inputs - list of property nodes
|
||||
# dest - where the bitmask is stored : property node
|
||||
var SwitchEncoder = {};
|
||||
SwitchEncoder.new = func (inputs, dest) {
|
||||
var obj = { parents : [SwitchEncoder],
|
||||
inputs : inputs,
|
||||
dest : dest };
|
||||
# Error checking.
|
||||
var bad = (obj.dest == nil);
|
||||
foreach (var i; inputs) {
|
||||
if (i == nil) { bad = 1; }
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
print("SwitchEncoder[");
|
||||
foreach (var i; inputs) {
|
||||
print(" ", debug.string(i));
|
||||
}
|
||||
print(" ", debug.string(obj.dest));
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
SwitchEncoder.update = func () {
|
||||
var v = 0;
|
||||
var b = 1;
|
||||
forindex (var i; me.inputs) {
|
||||
if (me.inputs[i].getBoolValue()) {
|
||||
v = v + b;
|
||||
}
|
||||
b *= 2;
|
||||
}
|
||||
me.dest.setIntValue(v);
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Switch decoder: Decodes a bitmask in an int property.
|
||||
# src - : property node
|
||||
# actions - list of actions : [func(b)]
|
||||
# Actions are triggered when their input bit change.
|
||||
# Due to interpolation the decoder needs to wait for a
|
||||
# stable input value.
|
||||
var SwitchDecoder = {};
|
||||
SwitchDecoder.new = func (src, actions) {
|
||||
var obj = { parents : [SwitchDecoder],
|
||||
wait : 0,
|
||||
old : 0,
|
||||
old_stable : 0,
|
||||
stable_since : 0,
|
||||
reset : 1,
|
||||
src : src,
|
||||
actions : actions,
|
||||
MIN_STABLE : 0.1 };
|
||||
# Error checking.
|
||||
var bad = (obj.src == nil);
|
||||
foreach (var a; obj.actions) {
|
||||
if (a == nil) { bad = 1; }
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
print("SwitchDecoder[");
|
||||
print(" ", debug.string(obj.src));
|
||||
foreach (var a; obj.actions) {
|
||||
print(" ", debug.string(a));
|
||||
}
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
SwitchDecoder.update = func () {
|
||||
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
|
||||
var v = me.src.getValue();
|
||||
if (!is_num(v)) return;
|
||||
|
||||
if ((me.old == v) and ((t - me.stable_since) > me.MIN_STABLE) and
|
||||
(me.wait == 1)) {
|
||||
var ov = me.old_stable;
|
||||
# Use this to improve.
|
||||
#<cptf> here's the boring version: var bittest = func(u, b) { while (b) { u = int(u / 2); b -= 1; } u != int(u / 2) * 2; }
|
||||
forindex (var i; me.actions) {
|
||||
var m = math.mod(v, 2);
|
||||
var om = math.mod(ov, 2);
|
||||
if ((m != om or me.reset)) { me.actions[i](m?1:0); }
|
||||
v = (v - m)/2;
|
||||
ov = (ov - om)/2;
|
||||
}
|
||||
me.old_stable = me.src.getValue();
|
||||
me.wait = 0;
|
||||
me.reset = 0;
|
||||
} elsif (me.old == v) {
|
||||
# Wait. This is either before the bitmask is stable or after
|
||||
# it has been processed.
|
||||
} else {
|
||||
me.stable_since = t;
|
||||
me.wait = 1;
|
||||
me.old = me.src.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Time division multiplexing encoder: Transmits a list of
|
||||
# properties over a MP enabled string property.
|
||||
# inputs - input properties : [property node]
|
||||
# dest - MP string prop : property node
|
||||
# Note: TDM can have high latency so it is best used for
|
||||
# non-time critical properties.
|
||||
var TDMEncoder = {};
|
||||
TDMEncoder.new = func (inputs, dest) {
|
||||
var obj = { parents : [TDMEncoder],
|
||||
inputs : inputs,
|
||||
channel : MessageChannel.new(dest,
|
||||
func (msg) {
|
||||
print("This should not happen!");
|
||||
}),
|
||||
MIN_INT : 0.25,
|
||||
last_time : 0,
|
||||
next_item : 0,
|
||||
old : [] };
|
||||
# Error checking.
|
||||
var bad = (dest == nil) or (obj.channel == nil);
|
||||
foreach (var i; inputs) {
|
||||
if (i == nil) { bad = 1; }
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
print("TDMEncoder[");
|
||||
foreach (var i; inputs) {
|
||||
print(" ", debug.string(i));
|
||||
}
|
||||
print(" ", debug.string(dest));
|
||||
print("]");
|
||||
}
|
||||
|
||||
setsize(obj.old, size(obj.inputs));
|
||||
|
||||
return obj;
|
||||
}
|
||||
TDMEncoder.update = func () {
|
||||
var t = getprop("/sim/time/elapsed-sec"); # NOTE: simulated time.
|
||||
if (t > me.last_time + me.MIN_INT) {
|
||||
var n = size(me.inputs);
|
||||
while (1) {
|
||||
var v = me.inputs[me.next_item].getValue();
|
||||
|
||||
if ((n <= 0) or (me.old[me.next_item] != v)) {
|
||||
# Set the MP properties to send the next item.
|
||||
me.channel.send(Binary.encodeByte(me.next_item) ~
|
||||
Binary.encodeDouble(v));
|
||||
|
||||
me.old[me.next_item] = v;
|
||||
|
||||
me.last_time = t;
|
||||
me.next_item += 1;
|
||||
if (me.next_item >= size(me.inputs)) { me.next_item = 0; }
|
||||
return;
|
||||
} else {
|
||||
# Search for changed property.
|
||||
n -= 1;
|
||||
me.next_item += 1;
|
||||
if (me.next_item >= size(me.inputs)) { me.next_item = 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
############################################################
|
||||
# Time division multiplexing decoder: Receives a list of
|
||||
# properties over a MP enabled string property.
|
||||
# src - MP string prop : property node
|
||||
# actions - list of actions : [func(v)]
|
||||
# An action is triggered when its value is received.
|
||||
# Note: TDM can have high latency so it is best used for
|
||||
# non-time critical properties.
|
||||
var TDMDecoder = {};
|
||||
TDMDecoder.new = func (src, actions) {
|
||||
var obj = { parents : [TDMDecoder],
|
||||
actions : actions };
|
||||
obj.channel = MessageChannel.new(src,
|
||||
func (msg) {
|
||||
obj.process(msg);
|
||||
});
|
||||
|
||||
# Error checking.
|
||||
var bad = (src == nil) or (obj.channel == nil);
|
||||
foreach (var a; actions) {
|
||||
if (a == nil) { bad = 1; }
|
||||
}
|
||||
|
||||
if (bad) {
|
||||
print("TDMDecoder[");
|
||||
print(" ", debug.string(src));
|
||||
foreach (var a; actions) {
|
||||
print(" ", debug.string(a));
|
||||
}
|
||||
print("]");
|
||||
fail();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
TDMDecoder.process = func (msg) {
|
||||
var v1 = Binary.decodeByte(msg);
|
||||
var v2 = Binary.decodeDouble(substr(msg, 1));
|
||||
# Trigger action.
|
||||
me.actions[v1](v2);
|
||||
}
|
||||
TDMDecoder.update = func {
|
||||
me.channel.update();
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Internal utility functions
|
||||
|
||||
var is_num = func (v) {
|
||||
return num(v) != nil;
|
||||
}
|
||||
|
||||
# fail causes a Nasal runtime error so we get a backtrace.
|
||||
var fail = func {
|
||||
error_detected_in_calling_context();
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Copilot selection dialog.
|
||||
#
|
||||
# Usage: dual_control_tools.copilot_dialog.show(<copilot type string>);
|
||||
#
|
||||
var COPILOT_DLG = 0;
|
||||
var copilot_dialog = {};
|
||||
############################################################
|
||||
copilot_dialog.init = func (copilot_type, x = nil, y = nil) {
|
||||
me.x = x;
|
||||
me.y = y;
|
||||
me.bg = [0, 0, 0, 0.3]; # background color
|
||||
me.fg = [[1.0, 1.0, 1.0, 1.0]];
|
||||
#
|
||||
# "private"
|
||||
if (contains(aircraft_dual_control, "copilot_view")) {
|
||||
me.title = "Pilot selection";
|
||||
} else {
|
||||
me.title = "Copilot selection";
|
||||
}
|
||||
me.basenode = props.globals.getNode("sim/remote", 1);
|
||||
me.dialog = nil;
|
||||
me.namenode = props.Node.new({"dialog-name" : me.title });
|
||||
me.listeners = [];
|
||||
me.copilot_type = copilot_type;
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog.create = func {
|
||||
if (me.dialog != nil)
|
||||
me.close();
|
||||
|
||||
me.dialog = gui.Widget.new();
|
||||
me.dialog.set("name", me.title);
|
||||
if (me.x != nil)
|
||||
me.dialog.set("x", me.x);
|
||||
if (me.y != nil)
|
||||
me.dialog.set("y", me.y);
|
||||
|
||||
me.dialog.set("layout", "vbox");
|
||||
me.dialog.set("default-padding", 0);
|
||||
var titlebar = me.dialog.addChild("group");
|
||||
titlebar.set("layout", "hbox");
|
||||
titlebar.addChild("empty").set("stretch", 1);
|
||||
if (contains(aircraft_dual_control, "copilot_view")) {
|
||||
titlebar.addChild("text").set("label", "Book your flight");
|
||||
} else {
|
||||
titlebar.addChild("text").set("label", "Passengers online");
|
||||
}
|
||||
var w = titlebar.addChild("button");
|
||||
w.set("pref-width", 16);
|
||||
w.set("pref-height", 16);
|
||||
w.set("legend", "");
|
||||
w.set("default", 0);
|
||||
w.set("key", "esc");
|
||||
w.setBinding("nasal", "dual_control_tools.copilot_dialog.destroy(); ");
|
||||
w.setBinding("dialog-close");
|
||||
me.dialog.addChild("hrule");
|
||||
|
||||
var content = me.dialog.addChild("group");
|
||||
content.set("layout", "vbox");
|
||||
content.set("halign", "center");
|
||||
content.set("default-padding", 5);
|
||||
|
||||
# Generate the dialog contents.
|
||||
me.players = me.find_copilot_players();
|
||||
var i = 0;
|
||||
var tmpbase = me.basenode.getNode("dialog", 1);
|
||||
var selected = me.basenode.getNode("pilot-callsign").getValue();
|
||||
foreach (var p; me.players) {
|
||||
var tmp = tmpbase.getNode("b[" ~ i ~ "]", 1);
|
||||
tmp.setBoolValue(streq(selected, p));
|
||||
var w = content.addChild("checkbox");
|
||||
w.node.setValues({"label" : p,
|
||||
"halign" : "left",
|
||||
"property" : tmp.getPath()});
|
||||
w.setBinding
|
||||
("nasal",
|
||||
"dual_control_tools.copilot_dialog.select_action(" ~ i ~ ");");
|
||||
i = i + 1;
|
||||
}
|
||||
me.dialog.addChild("hrule");
|
||||
|
||||
# Display the dialog.
|
||||
fgcommand("dialog-new", me.dialog.prop());
|
||||
fgcommand("dialog-show", me.namenode);
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog.close = func {
|
||||
fgcommand("dialog-close", me.namenode);
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog.destroy = func {
|
||||
COPILOT_DLG = 0;
|
||||
me.close();
|
||||
foreach(var l; me.listeners)
|
||||
removelistener(l);
|
||||
delete(gui.dialog, "\"" ~ me.title ~ "\"");
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog.show = func (copilot_type) {
|
||||
# print("Showing MPCopilots dialog!");
|
||||
if (!COPILOT_DLG) {
|
||||
COPILOT_DLG = int(getprop("/sim/time/elapsed-sec"));
|
||||
me.init(copilot_type);
|
||||
me.create();
|
||||
me._update_(COPILOT_DLG);
|
||||
}
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog._redraw_ = func {
|
||||
if (me.dialog != nil) {
|
||||
me.close();
|
||||
me.create();
|
||||
}
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog._update_ = func (id) {
|
||||
if (COPILOT_DLG != id) return;
|
||||
me._redraw_();
|
||||
settimer(func { me._update_(id); }, 4.1);
|
||||
}
|
||||
############################################################
|
||||
copilot_dialog.select_action = func (n) {
|
||||
var selected = me.basenode.getNode("pilot-callsign").getValue();
|
||||
var bs = me.basenode.getNode("dialog").getChildren();
|
||||
# Assumption: There are two true b:s or none. The one not matching selected
|
||||
# is the new selection.
|
||||
var i = 0;
|
||||
me.basenode.getNode("pilot-callsign").setValue("");
|
||||
foreach (var b; bs) {
|
||||
if (!b.getValue() and (i == n)) {
|
||||
b.setValue(1);
|
||||
me.basenode.getNode("pilot-callsign").setValue(me.players[i]);
|
||||
} else {
|
||||
b.setValue(0);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
dual_control.main.reset();
|
||||
me._redraw_();
|
||||
}
|
||||
############################################################
|
||||
# Return a list containing all nearby copilot players of the right type.
|
||||
copilot_dialog.find_copilot_players = func {
|
||||
var mpplayers =
|
||||
props.globals.getNode("ai/models").getChildren("multiplayer");
|
||||
|
||||
var res = [];
|
||||
foreach (var pilot; mpplayers) {
|
||||
if ((pilot.getNode("valid") != nil) and
|
||||
(pilot.getNode("valid").getValue()) and
|
||||
(pilot.getNode("sim/model/path") != nil)) {
|
||||
var type = pilot.getNode("sim/model/path").getValue();
|
||||
|
||||
if (type == me.copilot_type) {
|
||||
append(res, pilot.getNode("callsign").getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
# debug.dump(res);
|
||||
return res;
|
||||
}
|
||||
###############################################################################
|
||||
7564
test/fmz.nas
Normal file
7564
test/fmz.nas
Normal file
File diff suppressed because it is too large
Load Diff
195
test/json.nas
Normal file
195
test/json.nas
Normal file
@@ -0,0 +1,195 @@
|
||||
#lib json.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:[],
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if(me.ptr>=me.size)
|
||||
{
|
||||
me.token.content="";
|
||||
me.token.type="eof";
|
||||
return;
|
||||
}
|
||||
|
||||
if(me.text[me.ptr]=='{')
|
||||
{
|
||||
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]!='\"')
|
||||
{
|
||||
s~=me.text[me.ptr];
|
||||
me.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]=='.'))
|
||||
{
|
||||
s~=me.text[me.ptr];
|
||||
me.ptr+=1;
|
||||
}
|
||||
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")
|
||||
{
|
||||
append(vec,me.token.content);
|
||||
me.next();
|
||||
}
|
||||
}
|
||||
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")
|
||||
{
|
||||
hash[name]=me.token.content;
|
||||
me.next();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
json.parse=func()
|
||||
{
|
||||
me.content={};
|
||||
me.next();
|
||||
me.match("left brace");
|
||||
me.member(me.content);
|
||||
while(me.token.type=="comma")
|
||||
{
|
||||
me.match("comma");
|
||||
me.member(me.content);
|
||||
}
|
||||
me.match("right brace");
|
||||
return;
|
||||
}
|
||||
183
test/lexer.nas
Normal file
183
test/lexer.nas
Normal file
@@ -0,0 +1,183 @@
|
||||
import("lib.nas");
|
||||
|
||||
var s=io.fin("a.nas");
|
||||
s=split('',s);
|
||||
var len=size(s);
|
||||
var ptr=0;
|
||||
|
||||
var jump_note=func()
|
||||
{
|
||||
while(ptr<len and s[ptr]!='\n')
|
||||
ptr+=1;
|
||||
ptr+=1;
|
||||
return;
|
||||
}
|
||||
|
||||
var generate_id=func()
|
||||
{
|
||||
var tmp="";
|
||||
while(ptr<len)
|
||||
{
|
||||
if('a'<=s[ptr] and s[ptr]<='z'
|
||||
or 'A'<=s[ptr] and s[ptr]<='Z'
|
||||
or s[ptr]=='_'
|
||||
or '0'<=s[ptr] and s[ptr]<='9')
|
||||
tmp~=s[ptr];
|
||||
else
|
||||
break;
|
||||
ptr+=1;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
var generate_str=func()
|
||||
{
|
||||
var tok_str="";
|
||||
var mark=s[ptr];
|
||||
ptr+=1;
|
||||
while(ptr<len and s[ptr]!=mark)
|
||||
{
|
||||
if(s[ptr]=='\\')
|
||||
{
|
||||
ptr+=1;
|
||||
if(s[ptr]=='a') tok_str~='\a';
|
||||
elsif(s[ptr]=='b') tok_str~='\b';
|
||||
elsif(s[ptr]=='f') tok_str~='\f';
|
||||
elsif(s[ptr]=='n') tok_str~='\n';
|
||||
elsif(s[ptr]=='r') tok_str~='\r';
|
||||
elsif(s[ptr]=='t') tok_str~='\t';
|
||||
elsif(s[ptr]=='v') tok_str~='\v';
|
||||
elsif(s[ptr]=='?') tok_str~='?';
|
||||
elsif(s[ptr]=='0') tok_str~='\0';
|
||||
elsif(s[ptr]=='\\') tok_str~='\\';
|
||||
elsif(s[ptr]=='\'') tok_str~='\'';
|
||||
elsif(s[ptr]=='\"') tok_str~='\"';
|
||||
else tok_str~=s[ptr];
|
||||
}
|
||||
else
|
||||
tok_str~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
if(ptr>=len)
|
||||
print("read eof when generating string.");
|
||||
ptr+=1;
|
||||
return tok_str;
|
||||
}
|
||||
|
||||
var generate_number=func()
|
||||
{
|
||||
var number=s[ptr];
|
||||
ptr+=1;
|
||||
if(s[ptr]=='x')
|
||||
{
|
||||
ptr+=1;
|
||||
while(ptr<len and ('a'<=s[ptr] and s[ptr]<='f' or '0'<=s[ptr] and s[ptr]<='9'))
|
||||
{
|
||||
number~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
return num(number);
|
||||
}
|
||||
elsif(s[ptr]=='o')
|
||||
{
|
||||
ptr+=1;
|
||||
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='7'))
|
||||
{
|
||||
number~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
return num(number);
|
||||
}
|
||||
|
||||
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='9'))
|
||||
{
|
||||
number~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
if(s[ptr]=='.')
|
||||
number~=s[ptr];
|
||||
else
|
||||
return num(number);
|
||||
ptr+=1;
|
||||
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='9'))
|
||||
{
|
||||
number~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
if(s[ptr]=='e' or s[ptr]=='E')
|
||||
number~=s[ptr];
|
||||
else
|
||||
return num(number);
|
||||
ptr+=1;
|
||||
if(s[ptr]=='-' or s[ptr]=='+')
|
||||
{
|
||||
number~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
while(ptr<len and ('0'<=s[ptr] and s[ptr]<='9'))
|
||||
{
|
||||
number~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
return num(number);
|
||||
}
|
||||
|
||||
var generate_operator=func()
|
||||
{
|
||||
var tmp="";
|
||||
if(s[ptr]=='+' or s[ptr]=='-' or s[ptr]=='~' or s[ptr]=='/' or s[ptr]=='*' or s[ptr]=='>' or s[ptr]=='<' or s[ptr]=='!' or s[ptr]=='=')
|
||||
{
|
||||
tmp=s[ptr];
|
||||
ptr+=1;
|
||||
if(ptr<len and s[ptr]=='=')
|
||||
{
|
||||
tmp~=s[ptr];
|
||||
ptr+=1;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
elsif(s[ptr]=='.')
|
||||
{
|
||||
if(ptr+2<len and s[ptr+1]=='.' and s[ptr+2]=='.')
|
||||
{
|
||||
tmp='...';
|
||||
ptr+=3;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp='.';
|
||||
ptr+=1;
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
elsif(s[ptr]!=' ' and s[ptr]!='\t' and s[ptr]!='\n' and s[ptr]!='\r' and s[ptr][0]>0)
|
||||
tmp=s[ptr];
|
||||
ptr+=1;
|
||||
return tmp;
|
||||
}
|
||||
var cnt=0;
|
||||
var token=[];
|
||||
while(ptr<len)
|
||||
{
|
||||
if(s[ptr]=='#')
|
||||
jump_note();
|
||||
elsif('a'<=s[ptr] and s[ptr]<='z' or 'A'<=s[ptr] and s[ptr]<='Z' or s[ptr]=='_')
|
||||
append(token,generate_id());
|
||||
elsif(s[ptr]=='\'' or s[ptr]=='\"')
|
||||
append(token,generate_str());
|
||||
elsif('0'<=s[ptr] and s[ptr]<='9')
|
||||
append(token,generate_number());
|
||||
else
|
||||
{
|
||||
var tmp=generate_operator();
|
||||
if(size(tmp))
|
||||
append(token,tmp);
|
||||
}
|
||||
if(ptr>=len)
|
||||
break;
|
||||
}
|
||||
foreach(var i;token)
|
||||
{
|
||||
print("(",cnt," | ",i,")");
|
||||
cnt+=1;
|
||||
}
|
||||
167
test/lib.nas
Normal file
167
test/lib.nas
Normal file
@@ -0,0 +1,167 @@
|
||||
var import=func(filename)
|
||||
{
|
||||
nasal_call_import(filename);
|
||||
return nil;
|
||||
}
|
||||
var print=func(elements...)
|
||||
{
|
||||
nasal_call_builtin_std_cout(elements);
|
||||
return nil;
|
||||
};
|
||||
var append=func(vector,elements...)
|
||||
{
|
||||
nasal_call_builtin_push_back(vector,elements);
|
||||
return nil;
|
||||
}
|
||||
var setsize=func(vector,size)
|
||||
{
|
||||
nasal_call_builtin_set_size(vector,size);
|
||||
return nil;
|
||||
}
|
||||
var system=func(str)
|
||||
{
|
||||
nasal_call_builtin_system(str);
|
||||
return;
|
||||
}
|
||||
var input=func()
|
||||
{
|
||||
return nasal_call_builtin_input();
|
||||
}
|
||||
var sleep=func(duration)
|
||||
{
|
||||
nasal_call_builtin_sleep(duration);
|
||||
return;
|
||||
}
|
||||
var split=func(delimeter,string)
|
||||
{
|
||||
return nasal_call_builtin_split(delimeter,string);
|
||||
}
|
||||
var rand=func(seed=nil)
|
||||
{
|
||||
return nasal_call_builtin_rand(seed);
|
||||
}
|
||||
var id=func(thing)
|
||||
{
|
||||
return nasal_call_builtin_get_id(thing);
|
||||
}
|
||||
var int=func(value)
|
||||
{
|
||||
return nasal_call_builtin_trans_int(value);
|
||||
}
|
||||
var num=func(value)
|
||||
{
|
||||
return nasal_call_builtin_trans_num(value);
|
||||
}
|
||||
var pop=func(vector)
|
||||
{
|
||||
return nasal_call_builtin_pop_back(vector);
|
||||
}
|
||||
var str=func(number)
|
||||
{
|
||||
return nasal_call_builtin_trans_str(number);
|
||||
}
|
||||
var size=func(object)
|
||||
{
|
||||
return nasal_call_builtin_size(object);
|
||||
}
|
||||
var contains=func(hash,key)
|
||||
{
|
||||
return nasal_call_builtin_contains(hash,key);
|
||||
}
|
||||
var delete=func(hash,key)
|
||||
{
|
||||
nasal_call_builtin_delete(hash,key);
|
||||
return;
|
||||
}
|
||||
var keys=func(hash)
|
||||
{
|
||||
return nasal_call_builtin_get_keys(hash);
|
||||
}
|
||||
var time=func(begin_time)
|
||||
{
|
||||
return nasal_call_builtin_time(begin_time);
|
||||
}
|
||||
var die=func(str)
|
||||
{
|
||||
nasal_call_builtin_die(str);
|
||||
return nil;
|
||||
}
|
||||
var typeof=func(object)
|
||||
{
|
||||
return nasal_call_builtin_type(object);
|
||||
}
|
||||
var substr=func(str,begin,length)
|
||||
{
|
||||
return nasal_call_builtin_substr(str,begin,length);
|
||||
}
|
||||
|
||||
var io=
|
||||
{
|
||||
fin:func(filename)
|
||||
{
|
||||
return nasal_call_builtin_finput(filename);
|
||||
},
|
||||
fout:func(filename,str)
|
||||
{
|
||||
nasal_call_builtin_foutput(filename,str);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
var bits=
|
||||
{
|
||||
bitxor:func(a,b)
|
||||
{
|
||||
return nasal_call_builtin_xor(a,b);
|
||||
},
|
||||
bitand:func(a,b)
|
||||
{
|
||||
return nasal_call_builtin_and(a,b);
|
||||
},
|
||||
bitor:func(a,b)
|
||||
{
|
||||
return nasal_call_builtin_or(a,b);
|
||||
},
|
||||
bitnand:func(a,b)
|
||||
{
|
||||
return nasal_call_builtin_nand(a,b);
|
||||
},
|
||||
bitnot:func(a)
|
||||
{
|
||||
return nasal_call_builtin_not(a);
|
||||
}
|
||||
};
|
||||
|
||||
var math=
|
||||
{
|
||||
e:2.7182818284590452354,
|
||||
pi:3.14159265358979323846,
|
||||
sin:func(x)
|
||||
{
|
||||
return nasal_call_builtin_sin(x);
|
||||
},
|
||||
cos:func(x)
|
||||
{
|
||||
return nasal_call_builtin_cos(x);
|
||||
},
|
||||
tan:func(x)
|
||||
{
|
||||
return nasal_call_builtin_tan(x);
|
||||
},
|
||||
exp:func(x)
|
||||
{
|
||||
return nasal_call_builtin_exp(x);
|
||||
},
|
||||
ln:func(x)
|
||||
{
|
||||
return nasal_call_builtin_cpp_math_ln(x);
|
||||
},
|
||||
sqrt:func(x)
|
||||
{
|
||||
return nasal_call_builtin_cpp_math_sqrt(x);
|
||||
},
|
||||
atan2:func(x,y)
|
||||
{
|
||||
return nasal_call_builtin_cpp_atan2(x,y);
|
||||
},
|
||||
};
|
||||
@@ -1,38 +1,30 @@
|
||||
while(n==1 )
|
||||
for(;;)break;
|
||||
for(;;)
|
||||
{
|
||||
i=i+1;
|
||||
f(i);
|
||||
print("str");
|
||||
var a=1;
|
||||
break;
|
||||
}
|
||||
for(var i=1;;)break;
|
||||
for(var i=1;;i+=1)break;
|
||||
for(var i=1;i<10;i+=1)print(i);
|
||||
|
||||
while(1)break;
|
||||
var j=0;
|
||||
while(j<10)
|
||||
{
|
||||
print(j);
|
||||
j+=1;
|
||||
}
|
||||
|
||||
while(n==1 and "str"==str)
|
||||
forindex(var j;[0,1,2,3])print(j);
|
||||
forindex(var j;[0,1,2,3])
|
||||
{
|
||||
print("str");
|
||||
var a=j;
|
||||
print(a*a);
|
||||
}
|
||||
|
||||
i+=i1;
|
||||
i+=i.i[0];
|
||||
i=i.i[0].i(0);
|
||||
var hash={
|
||||
f:func {var e=1;return 0;},
|
||||
};
|
||||
for(var i=0;i<1024;i+=1)
|
||||
foreach(var j;[0,1,2,3])print([0,1,2,3][j]);
|
||||
foreach(var j;[0,1,2,3])
|
||||
{
|
||||
print(i);
|
||||
var a=[0,1,2,3][j];
|
||||
print(a*a-1);
|
||||
}
|
||||
for(var i=0;(2*512)>=i;i+=1)
|
||||
{
|
||||
print(i);
|
||||
}
|
||||
foreach(var i;[1+(1+1),2,3,4])
|
||||
{
|
||||
print(i);
|
||||
}
|
||||
forindex(var i=list;[1,2,3,4])
|
||||
{
|
||||
print(i[0]);
|
||||
}
|
||||
while(!id)
|
||||
{
|
||||
print("yes");
|
||||
}
|
||||
382
test/main.nas
Normal file
382
test/main.nas
Normal file
@@ -0,0 +1,382 @@
|
||||
# game left in corner by ValKmjolnir
|
||||
# 2020
|
||||
|
||||
# lib function defined here
|
||||
var print=func(elements...)
|
||||
{
|
||||
nasal_call_builtin_std_cout(elements);
|
||||
return nil;
|
||||
};
|
||||
var append=func(vector,elements...)
|
||||
{
|
||||
nasal_call_builtin_push_back(vector,elements);
|
||||
return nil;
|
||||
}
|
||||
var setsize=func(vector,size)
|
||||
{
|
||||
nasal_call_builtin_set_size(vector,size);
|
||||
return nil;
|
||||
}
|
||||
var system=func(str)
|
||||
{
|
||||
nasal_call_builtin_system(str);
|
||||
return;
|
||||
}
|
||||
var sleep=func(duration)
|
||||
{
|
||||
nasal_call_builtin_sleep(duration);
|
||||
return;
|
||||
}
|
||||
var input=func()
|
||||
{
|
||||
return nasal_call_builtin_input();
|
||||
}
|
||||
var io=
|
||||
{
|
||||
fin:func(filename)
|
||||
{
|
||||
return nasal_call_builtin_finput(filename);
|
||||
},
|
||||
fout:func(filename,str)
|
||||
{
|
||||
nasal_call_builtin_foutput(filename,str);
|
||||
return;
|
||||
}
|
||||
};
|
||||
var int=func(str)
|
||||
{
|
||||
return str+0;
|
||||
}
|
||||
var str=func(num)
|
||||
{
|
||||
return num~'';
|
||||
}
|
||||
# string split
|
||||
|
||||
# game elements defined here
|
||||
var role_property=
|
||||
{
|
||||
health:100,
|
||||
mood:100,
|
||||
satiety:100,
|
||||
thirst:100,
|
||||
health_change:func(x)
|
||||
{
|
||||
me.health+=x;
|
||||
if(me.health<0)
|
||||
me.health=0;
|
||||
elsif(me.health>100)
|
||||
me.health=100;
|
||||
return nil;
|
||||
},
|
||||
mood_change:func(x)
|
||||
{
|
||||
me.mood+=x;
|
||||
if(me.mood<0)
|
||||
me.mood=0;
|
||||
elsif(me.mood>100)
|
||||
me.mood=100;
|
||||
return nil;
|
||||
},
|
||||
satiety_change:func(x)
|
||||
{
|
||||
me.satiety+=x;
|
||||
if(me.satiety<0)
|
||||
me.satiety=0;
|
||||
elsif(me.satiety>100)
|
||||
me.satiety=100;
|
||||
return nil;
|
||||
},
|
||||
thirst_change:func(x)
|
||||
{
|
||||
me.thirst+=x;
|
||||
if(me.thirst<0)
|
||||
me.thirst=0;
|
||||
elsif(me.thirst>100)
|
||||
me.thirst=100;
|
||||
return nil;
|
||||
}
|
||||
};
|
||||
var screen=
|
||||
{
|
||||
picture:[],
|
||||
info_below_left:[],
|
||||
info_below_right:[],
|
||||
clear:func()
|
||||
{
|
||||
me.picture=[];
|
||||
me.info_below_left=[];
|
||||
me.info_below_right=[];
|
||||
return;
|
||||
},
|
||||
pic_addline:func(_str)
|
||||
{
|
||||
append(me.picture,_str);
|
||||
return;
|
||||
},
|
||||
left_add:func(_str)
|
||||
{
|
||||
append(me.info_below_left,_str);
|
||||
return;
|
||||
},
|
||||
right_add:func(_str)
|
||||
{
|
||||
append(me.info_below_right,_str);
|
||||
return;
|
||||
},
|
||||
prt_screen:func()
|
||||
{
|
||||
foreach(var i;me.picture)
|
||||
print(i);
|
||||
forindex(var i;me.info_below_left)
|
||||
print(me.info_below_left[i]~me.info_below_right[i]);
|
||||
return;
|
||||
}
|
||||
};
|
||||
var first_shown_info=func()
|
||||
{
|
||||
system("cls");
|
||||
var str_list=[
|
||||
"+-----------------------------------------------+",
|
||||
"| |",
|
||||
"| |",
|
||||
"| Let me tell you a story... |",
|
||||
"| A story that really happened many years ago...|",
|
||||
"| Nearly no one knows and cares about it... |",
|
||||
"| But some children may still suffer from... |",
|
||||
"| This kind of stories... |",
|
||||
"| And this kind of stories never stop hurting...|",
|
||||
"| People that are still alive... |",
|
||||
"| |",
|
||||
"| |",
|
||||
"+-----------------------------------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
print(i);
|
||||
return;
|
||||
}
|
||||
var generate_role_property=func()
|
||||
{
|
||||
screen.left_add("+-----------------------+");
|
||||
var str="";
|
||||
for(var i=10;i<=100;i+=10)
|
||||
{
|
||||
if(i<=role_property.health)
|
||||
str~="=";
|
||||
else
|
||||
str~=" ";
|
||||
}
|
||||
screen.left_add("|[health ]:"~str~" |");
|
||||
str="";
|
||||
for(var i=10;i<=100;i+=10)
|
||||
{
|
||||
if(i<=role_property.mood)
|
||||
str~="=";
|
||||
else
|
||||
str~=" ";
|
||||
}
|
||||
screen.left_add("|[mood ]:"~str~" |");
|
||||
str="";
|
||||
for(var i=10;i<=100;i+=10)
|
||||
{
|
||||
if(i<=role_property.satiety)
|
||||
str~="=";
|
||||
else
|
||||
str~=" ";
|
||||
}
|
||||
screen.left_add("|[satiety]:"~str~" |");
|
||||
str="";
|
||||
for(var i=10;i<=100;i+=10)
|
||||
{
|
||||
if(i<=role_property.thirst)
|
||||
str~="=";
|
||||
else
|
||||
str~=" ";
|
||||
}
|
||||
screen.left_add("|[thirst ]:"~str~" |");
|
||||
screen.left_add("+-----------------------+");
|
||||
return;
|
||||
}
|
||||
var generate_choose_list=func()
|
||||
{
|
||||
var str_list=[
|
||||
"-----------------------+",
|
||||
"[1]| next step |",
|
||||
"[2]| restart |",
|
||||
"[3]| store game |",
|
||||
"[4]| exit |",
|
||||
"-----------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
screen.right_add(i);
|
||||
return;
|
||||
}
|
||||
var next_step=func()
|
||||
{
|
||||
role_property.health_change(-1);
|
||||
role_property.mood_change(-1);
|
||||
role_property.satiety_change(-1);
|
||||
role_property.thirst_change(-10);
|
||||
var str_list=[
|
||||
"+-----------------------------------------------+",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"+-----------------------------------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
screen.pic_addline(i);
|
||||
return;
|
||||
}
|
||||
var restart=func()
|
||||
{
|
||||
role_property.health=100;
|
||||
role_property.mood=100;
|
||||
role_property.satiety=100;
|
||||
role_property.thirst=100;
|
||||
var str_list=[
|
||||
"+-----------------------------------------------+",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"+-----------------------------------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
screen.pic_addline(i);
|
||||
return;
|
||||
}
|
||||
var generate_incorrect_choice_screen=func()
|
||||
{
|
||||
var str_list=[
|
||||
"+-----------------------------------------------+",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| make a correct choice. |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"+-----------------------------------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
screen.pic_addline(i);
|
||||
}
|
||||
var generate_goodbye_screen=func()
|
||||
{
|
||||
var str_list=[
|
||||
"+-----------------------------------------------+",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| see you next life. |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"+-----------------------------------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
screen.pic_addline(i);
|
||||
}
|
||||
var store_file=func()
|
||||
{
|
||||
var str=role_property.health~'\n'~role_property.mood~'\n'~role_property.satiety~'\n'~role_property.thirst~'\n';
|
||||
io.fout("game-left-in-corner.glic",str);
|
||||
var str_list=[
|
||||
"+-----------------------------------------------+",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| data stored. |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"| |",
|
||||
"+-----------------------------------------------+"
|
||||
];
|
||||
foreach(var i;str_list)
|
||||
screen.pic_addline(i);
|
||||
return;
|
||||
}
|
||||
var get_file=func()
|
||||
{
|
||||
var str=io.fin("game-left-in-corner.glic");
|
||||
print(str);
|
||||
return;
|
||||
}
|
||||
var game_main=func()
|
||||
{
|
||||
first_shown_info();
|
||||
screen.clear();
|
||||
generate_role_property();
|
||||
generate_choose_list();
|
||||
screen.prt_screen();
|
||||
while(1)
|
||||
{
|
||||
screen.clear();
|
||||
print("|your choice[1|2|3|4]: |");
|
||||
var choice=input();
|
||||
if((choice!='1') and (choice!='2') and (choice!='3') and (choice!='4'))
|
||||
generate_incorrect_choice_screen();
|
||||
elsif(choice=='1')
|
||||
next_step();
|
||||
elsif(choice=='2')
|
||||
restart();
|
||||
elsif(choice=='3')
|
||||
store_file();
|
||||
elsif(choice=='4')
|
||||
{
|
||||
system("cls");
|
||||
screen.clear();
|
||||
generate_goodbye_screen();
|
||||
generate_role_property();
|
||||
generate_choose_list();
|
||||
screen.prt_screen();
|
||||
break;
|
||||
}
|
||||
system("cls");
|
||||
generate_role_property();
|
||||
generate_choose_list();
|
||||
screen.prt_screen();
|
||||
if(role_property.health==0 or role_property.mood==0 or role_property.satiety==0 or role_property.thirst==0)
|
||||
{
|
||||
print("|you died. |");
|
||||
print("+-----------------------------------------------+");
|
||||
system("pause");
|
||||
screen.clear();
|
||||
restart();
|
||||
system("cls");
|
||||
generate_role_property();
|
||||
generate_choose_list();
|
||||
screen.prt_screen();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
game_main();
|
||||
156
test/neo4j.nas
Normal file
156
test/neo4j.nas
Normal file
@@ -0,0 +1,156 @@
|
||||
import("lib.nas");
|
||||
|
||||
rand(time(0));
|
||||
var chartable=split('','abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
|
||||
var node=func(type)
|
||||
{
|
||||
var s="";
|
||||
for(var i=0;i<10;i+=1)
|
||||
s~=chartable[rand()*62];
|
||||
return {name:s,type:type,next:[]};
|
||||
}
|
||||
var film_node=[];
|
||||
for(var i=0;i<1000;i+=1)
|
||||
append(film_node,node("film"));
|
||||
var director_node=[];
|
||||
for(var i=0;i<400;i+=1)
|
||||
append(director_node,node("direct"));
|
||||
var actor_node=[];
|
||||
for(var i=0;i<2000;i+=1)
|
||||
append(actor_node,node("actor"));
|
||||
var writer_node=[];
|
||||
for(var i=0;i<300;i+=1)
|
||||
append(writer_node,node("writer"));
|
||||
var type_node=[];
|
||||
for(var i=0;i<20;i+=1)
|
||||
append(type_node,node("type"));
|
||||
var lang_node=[];
|
||||
for(var i=0;i<120;i+=1)
|
||||
append(lang_node,node("lang"));
|
||||
var country_node=[];
|
||||
for(var i=0;i<120;i+=1)
|
||||
append(country_node,node("country"));
|
||||
|
||||
func()
|
||||
{
|
||||
var director_size=size(director_node);
|
||||
var actor_size=size(actor_node);
|
||||
var writer_size=size(writer_node);
|
||||
var type_size=size(type_node);
|
||||
var lang_size=size(lang_node);
|
||||
var country_size=size(country_node);
|
||||
|
||||
var director_link=int(1+rand()*2);
|
||||
var actor_link=int(1+rand()*10);
|
||||
var writer_link=int(1+rand());
|
||||
var type_link=int(1+rand()*3);
|
||||
var lang_link=int(1+rand()*4);
|
||||
var country_link=int(1+rand()*2);
|
||||
foreach(var film;film_node)
|
||||
{
|
||||
for(var i=0;i<director_link;i+=1)
|
||||
{
|
||||
var director=director_node[rand()*director_size];
|
||||
append(film.next,director);
|
||||
append(director.next,film);
|
||||
}
|
||||
for(var i=0;i<actor_link;i+=1)
|
||||
{
|
||||
var actor=actor_node[rand()*actor_size];
|
||||
append(film.next,actor);
|
||||
append(actor.next,film);
|
||||
}
|
||||
for(var i=0;i<writer_link;i+=1)
|
||||
{
|
||||
var writer=writer_node[rand()*writer_size];
|
||||
append(film.next,writer);
|
||||
append(writer.next,film);
|
||||
}
|
||||
for(var i=0;i<type_link;i+=1)
|
||||
{
|
||||
var _type=type_node[rand()*type_size];
|
||||
append(film.next,_type);
|
||||
append(_type.next,film);
|
||||
}
|
||||
for(var i=0;i<lang_link;i+=1)
|
||||
{
|
||||
var lang=lang_node[rand()*lang_size];
|
||||
append(film.next,lang);
|
||||
append(lang.next,film);
|
||||
}
|
||||
for(var i=0;i<country_link;i+=1)
|
||||
{
|
||||
var country=country_node[rand()*country_size];
|
||||
append(film.next,country);
|
||||
append(country.next,film);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}();
|
||||
|
||||
|
||||
var film_list=[];
|
||||
var count_list=[];
|
||||
for(var i=0;i<10;i+=1)
|
||||
{
|
||||
append(film_list,film_node[i]);
|
||||
append(count_list,1);
|
||||
}
|
||||
|
||||
var sort_list=func(begin,end)
|
||||
{
|
||||
for(var i=begin;i<end;i+=1)
|
||||
{
|
||||
var index=i;
|
||||
for(var j=i+1;j<end;j+=1)
|
||||
if(count_list[index]<count_list[j])
|
||||
index=j;
|
||||
if(index!=i)
|
||||
{
|
||||
var tmp=film_list[i];
|
||||
film_list[i]=film_list[index];
|
||||
film_list[index]=tmp;
|
||||
tmp=count_list[i];
|
||||
count_list[i]=count_list[index];
|
||||
count_list[index]=tmp;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
var list_size=size(film_list);
|
||||
list_size=list_size>10?10:list_size;
|
||||
for(var i=0;i<list_size;i+=1)
|
||||
print(i,'\t:',film_list[i].name,'\t',count_list[i]);
|
||||
var choose=input();
|
||||
if(choose=="exit")
|
||||
break;
|
||||
if(num(choose)>=list_size)
|
||||
die("choose a correct index");
|
||||
var label_list=film_node[num(choose)].next;
|
||||
film_list=[];
|
||||
count_list=[];
|
||||
foreach(var label;label_list)
|
||||
foreach(var film;label.next)
|
||||
{
|
||||
var has=0;
|
||||
for(var i=0;i<size(film_list);i+=1)
|
||||
if(film_list[i].name==film.name)
|
||||
{
|
||||
has=1;
|
||||
count_list[i]+=rand();
|
||||
break;
|
||||
}
|
||||
if(has==0)
|
||||
{
|
||||
append(film_list,film);
|
||||
append(count_list,1);
|
||||
}
|
||||
}
|
||||
sort_list(0,size(film_list));
|
||||
}
|
||||
|
||||
foreach(var film;film_node)
|
||||
setsize(film.next,0);
|
||||
246
test/prop.nas
Normal file
246
test/prop.nas
Normal file
@@ -0,0 +1,246 @@
|
||||
import("lib.nas");
|
||||
|
||||
var property_tree=
|
||||
{
|
||||
accelerations:
|
||||
{
|
||||
'n-z-cg-fps_sec':0,
|
||||
ned:
|
||||
{
|
||||
'down-accel-fps_sec':0,
|
||||
'east-accel-fps_sec':0,
|
||||
'north-accel-fps_sec':0,
|
||||
},
|
||||
nlf:0,
|
||||
pilot:
|
||||
{
|
||||
'x-accel-fps_sec':0,
|
||||
'y-accel-fps_sec':0,
|
||||
'z-accel-fps_sec':0,
|
||||
},
|
||||
'pilot-g':1,
|
||||
'pilot-gdamped':1
|
||||
},
|
||||
ai:
|
||||
{
|
||||
models:
|
||||
{
|
||||
carrier:
|
||||
{
|
||||
callsign:'',
|
||||
controls:{},
|
||||
environment:{},
|
||||
id:2,
|
||||
name:'Nimitz',
|
||||
navaids:{},
|
||||
orientation:{},
|
||||
position:{},
|
||||
radar:{},
|
||||
sign:'CVN-68',
|
||||
sim:{},
|
||||
subID:0,
|
||||
submodels:
|
||||
{
|
||||
path:'',
|
||||
serviceable:1
|
||||
},
|
||||
'surface-positions':{},
|
||||
type:'AI',
|
||||
valid:1,
|
||||
velocities:{},
|
||||
waypoint:{}
|
||||
},
|
||||
'carrier[1]':
|
||||
{
|
||||
callsign:'',
|
||||
controls:{},
|
||||
environment:{},
|
||||
id:3,
|
||||
name:'Eisenhower',
|
||||
navaids:{},
|
||||
orientation:{},
|
||||
position:{},
|
||||
radar:{},
|
||||
sign:'CVN-69',
|
||||
sim:{},
|
||||
subID:0,
|
||||
submodels:
|
||||
{
|
||||
path:'',
|
||||
serviceable:0
|
||||
},
|
||||
'surface-positions':{},
|
||||
type:'AI',
|
||||
valid:1,
|
||||
velocities:{},
|
||||
waypoint:{}
|
||||
},
|
||||
count:2,
|
||||
'model-added':'/ai[0]/models[0]/carrier[1]',
|
||||
'model-removed':nil,
|
||||
'num-players':0
|
||||
},
|
||||
submodels:
|
||||
{
|
||||
contrails:0
|
||||
},
|
||||
},
|
||||
aircraft:
|
||||
{
|
||||
icao:
|
||||
{
|
||||
equipment:'SDFGY',
|
||||
surveillance:'S',
|
||||
type:'ZZZZ',
|
||||
'wake-turbulence-category':'L'
|
||||
},
|
||||
performance:
|
||||
{
|
||||
approach:
|
||||
{
|
||||
'airspeed-knots':150,
|
||||
},
|
||||
climb:'\n\t\t\t\n\t\t\t',
|
||||
cruise:
|
||||
{
|
||||
'airspeed-knots':1000,
|
||||
'altitude-ft':4500,
|
||||
},
|
||||
descent:'\n\t\t\t\n\t\t\t',
|
||||
maximum:'\n\t\t\t\n\t\t\t',
|
||||
minimum:'\n\t\t\t\n\t\t\t',
|
||||
},
|
||||
settings:
|
||||
{
|
||||
fuel_persistent:0,
|
||||
ground_services_persistent:0,
|
||||
radio_persistent:0,
|
||||
tooltips:1,
|
||||
weight_persistent:0
|
||||
}
|
||||
},
|
||||
autopilot:
|
||||
{
|
||||
internal:{},
|
||||
locks:{},
|
||||
'route-manager':{},
|
||||
settings:{},
|
||||
'target-tracking':{},
|
||||
},
|
||||
canvas:
|
||||
{
|
||||
'by-index':
|
||||
{
|
||||
texture:
|
||||
{
|
||||
background:'rgba(0,0,0,0)',
|
||||
group:{},
|
||||
name:'Tooltip',
|
||||
placement:{},
|
||||
size:600,
|
||||
'size[1]':200,
|
||||
status:0,
|
||||
'status-msg':'OK',
|
||||
view:300,
|
||||
'view[1]':100
|
||||
},
|
||||
'texture[1]':
|
||||
{
|
||||
background:'rgba(0,0,0,0)',
|
||||
group:{},
|
||||
mipmapping:1,
|
||||
name:'SymbolCache1024x1024',
|
||||
placement:{},
|
||||
size:1024,
|
||||
'size[1]':1024,
|
||||
status:0,
|
||||
'status-msg':'OK',
|
||||
view:1024,
|
||||
'view[1]':1024
|
||||
},
|
||||
'texture[2]':
|
||||
{
|
||||
background:'rgba(0,0,0,0)',
|
||||
group:{},
|
||||
mipmapping:1,
|
||||
name:'SymbolCache1024x1024',
|
||||
placement:{},
|
||||
size:1024,
|
||||
'size[1]':1024,
|
||||
status:0,
|
||||
'status-msg':'OK',
|
||||
view:1024,
|
||||
'view[1]':1024
|
||||
},
|
||||
}
|
||||
},
|
||||
command:{},
|
||||
consumables:{},
|
||||
controls:{},
|
||||
cursor:'Aircraft/ufo/Models/cursor.ac',
|
||||
devices:{},
|
||||
earthview:{},
|
||||
engines:{},
|
||||
environment:{},
|
||||
ephemeris:{},
|
||||
fdm:{},
|
||||
gear:{},
|
||||
hazards:{},
|
||||
input:{},
|
||||
instrumentation:{},
|
||||
'local-weather':{},
|
||||
logging:{},
|
||||
models:{},
|
||||
nasal:{},
|
||||
orientation:{},
|
||||
position:{},
|
||||
rendering:{},
|
||||
scenery:{},
|
||||
sim:{},
|
||||
source:'Models',
|
||||
'surface-positions':{},
|
||||
systems:{},
|
||||
velocities:{},
|
||||
};
|
||||
|
||||
var setprop=func(prop,value)
|
||||
{
|
||||
if(type(prop)!="string")
|
||||
die("setprop: prop is not a string");
|
||||
var path=split('/',prop);
|
||||
var tmp=property_tree;
|
||||
var path_size=size(path);
|
||||
for(var i=0;i<path_size-1;i+=1)
|
||||
tmp=tmp[path[i]];
|
||||
tmp[path[path_size-1]]=value;
|
||||
return;
|
||||
}
|
||||
var getprop=func(prop)
|
||||
{
|
||||
if(type(prop)!="string")
|
||||
die("getprop: prop is not a string");
|
||||
var path=split('/',prop);
|
||||
var tmp=property_tree;
|
||||
foreach(var i;path)
|
||||
tmp=tmp[i];
|
||||
return tmp;
|
||||
}
|
||||
setprop("aircraft/icao/type",'IDG MD-11');
|
||||
|
||||
var print_prop=func(depth,prop)
|
||||
{
|
||||
var s='';
|
||||
for(var i=0;i<depth;i+=1)
|
||||
s~='| ';
|
||||
if(type(prop)!="hash")
|
||||
return;
|
||||
var m=keys(prop);
|
||||
foreach(var elem;m)
|
||||
{
|
||||
print(s,elem,':',prop[elem]);
|
||||
print_prop(depth+1,prop[elem]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
print_prop(0,property_tree);
|
||||
576
test/props.nas
Normal file
576
test/props.nas
Normal file
@@ -0,0 +1,576 @@
|
||||
##
|
||||
# Node class definition. The class methods simply wrap the
|
||||
# low level extension functions which work on a "ghost" handle to a
|
||||
# SGPropertyNode object stored in the _g field.
|
||||
#
|
||||
# Not all of the features of SGPropertyNode are supported. There is
|
||||
# no support for ties, obviously, as that wouldn't make much sense
|
||||
# from a Nasal context. The various get/set methods work only on the
|
||||
# local node, there is no equivalent of the "relative path" variants
|
||||
# available in C++; just use node.getNode(path).whatever() instead.
|
||||
#
|
||||
var Node = {
|
||||
getNode : func wrap(_getNode(me._g, arg)),
|
||||
getParent : func wrap(_getParent(me._g, arg)),
|
||||
getChild : func wrap(_getChild(me._g, arg)),
|
||||
getChildren : func wrap(_getChildren(me._g, arg)),
|
||||
setChildren : func wrap(_setChildren(me._g, arg)),
|
||||
addChild : func wrap(_addChild(me._g, arg)),
|
||||
addChildren : func wrap(_addChildren(me._g, arg)),
|
||||
removeChild : func wrap(_removeChild(me._g, arg)),
|
||||
removeChildren : func wrap(_removeChildren(me._g, arg)),
|
||||
removeAllChildren: func wrap(_removeAllChildren(me._g, arg)),
|
||||
getAliasTarget : func wrap(_getAliasTarget(me._g, arg)),
|
||||
|
||||
getName : func _getName(me._g, arg),
|
||||
getIndex : func _getIndex(me._g, arg),
|
||||
getType : func _getType(me._g, arg),
|
||||
getAttribute : func _getAttribute(me._g, arg),
|
||||
setAttribute : func _setAttribute(me._g, arg),
|
||||
getValue : func _getValue(me._g, arg),
|
||||
setValue : func _setValue(me._g, arg),
|
||||
setValues : func _setValues(me._g, arg),
|
||||
setIntValue : func _setIntValue(me._g, arg),
|
||||
setBoolValue : func _setBoolValue(me._g, arg),
|
||||
setDoubleValue : func _setDoubleValue(me._g, arg),
|
||||
unalias : func _unalias(me._g, arg),
|
||||
alias : func(n) _alias(me._g, [isa(n, Node) ? n._g : n]),
|
||||
equals : func(n) _equals(me._g, [isa(n, Node) ? n._g : n]),
|
||||
clearValue : func _alias(me._g, [_globals()]) and me.unalias(),
|
||||
|
||||
getPath : func {
|
||||
var (name, index, parent) = (me.getName(), me.getIndex(), me.getParent());
|
||||
if(index != 0) { name ~= "[" ~ index ~ "]"; }
|
||||
if(parent != nil) { name = parent.getPath() ~ "/" ~ name; }
|
||||
return name;
|
||||
},
|
||||
|
||||
getBoolValue : func {
|
||||
var val = me.getValue();
|
||||
var mytype = me.getType();
|
||||
if((mytype == "STRING" or mytype == "UNSPECIFIED") and val == "false") return 0;
|
||||
return !!val;
|
||||
},
|
||||
|
||||
remove : func {
|
||||
if((var p = me.getParent()) == nil) return nil;
|
||||
p.removeChild(me.getName(), me.getIndex());
|
||||
},
|
||||
};
|
||||
|
||||
##
|
||||
# Static constructor for a Node object. Accepts a Nasal hash
|
||||
# expression to initialize the object a-la setValues().
|
||||
#
|
||||
Node.new = func(values = nil) {
|
||||
var result = wrapNode(_new());
|
||||
if(typeof(values) == "hash")
|
||||
result.setValues(values);
|
||||
return result;
|
||||
}
|
||||
|
||||
##
|
||||
# Counter piece of setValues(). Returns a hash with all values
|
||||
# in the subtree. Nodes with same name are returned as vector,
|
||||
# where the original node indices are lost. The function should
|
||||
# only be used if all or almost all values are needed, and never
|
||||
# in performance-critical code paths. If it's called on a node
|
||||
# without children, then the result is equivalent to getValue().
|
||||
#
|
||||
Node.getValues = func {
|
||||
var children = me.getChildren();
|
||||
if(!size(children)) return me.getValue();
|
||||
var val = {};
|
||||
var numchld = {};
|
||||
foreach(var c; children) {
|
||||
var name = c.getName();
|
||||
if(contains(numchld, name)) { var nc = numchld[name]; }
|
||||
else {
|
||||
var nc = size(me.getChildren(name));
|
||||
numchld[name] = nc;
|
||||
if(nc > 1 and !contains(val, name)) val[name] = [];
|
||||
}
|
||||
if(nc > 1) append(val[name], c.getValues());
|
||||
else val[name] = c.getValues();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
##
|
||||
# Initializes property if it's still undefined. First argument
|
||||
# is a property name/path. It can also be nil or an empty string,
|
||||
# in which case the node itself gets initialized, rather than one
|
||||
# of its children. Second argument is the default value. The third,
|
||||
# optional argument is a property type (one of "STRING", "DOUBLE",
|
||||
# "INT", or "BOOL"). If it is omitted, then "DOUBLE" is used for
|
||||
# numbers, and STRING for everything else. Returns the property
|
||||
# as props.Node. The fourth optional argument enforces a type if
|
||||
# non-zero.
|
||||
#
|
||||
Node.initNode = func(path = nil, value = 0, type = nil, force = 0) {
|
||||
var prop = me.getNode(path or "", 1);
|
||||
if(prop.getType() != "NONE") value = prop.getValue();
|
||||
if(force) prop.clearValue();
|
||||
if(type == nil) prop.setValue(value);
|
||||
elsif(type == "DOUBLE") prop.setDoubleValue(value);
|
||||
elsif(type == "INT") prop.setIntValue(value);
|
||||
elsif(type == "BOOL") prop.setBoolValue(value);
|
||||
elsif(type == "STRING") prop.setValue("" ~ value);
|
||||
else die("initNode(): unsupported type '" ~ type ~ "'");
|
||||
return prop;
|
||||
}
|
||||
|
||||
##
|
||||
# Useful debugging utility. Recursively dumps the full state of a
|
||||
# Node object to the console. Try binding "props.dump(props.globals)"
|
||||
# to a key for a fun hack.
|
||||
#
|
||||
var dump = func {
|
||||
if(size(arg) == 1) { prefix = ""; node = arg[0]; }
|
||||
else { prefix = arg[0]; node = arg[1]; }
|
||||
|
||||
index = node.getIndex();
|
||||
type = node.getType();
|
||||
name = node.getName();
|
||||
val = node.getValue();
|
||||
|
||||
if(val == nil) { val = "nil"; }
|
||||
name = prefix ~ name;
|
||||
if(index > 0) { name = name ~ "[" ~ index ~ "]"; }
|
||||
print(name, " {", type, "} = ", val);
|
||||
|
||||
# Don't recurse into aliases, lest we get stuck in a loop
|
||||
if(type != "ALIAS") {
|
||||
children = node.getChildren();
|
||||
foreach(c; children) { dump(name ~ "/", c); }
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
# Recursively copy property branch from source Node to
|
||||
# destination Node. Doesn't copy aliases. Copies attributes
|
||||
# if optional third argument is set and non-zero.
|
||||
#
|
||||
var copy = func(src, dest, attr = 0) {
|
||||
foreach(var c; src.getChildren()) {
|
||||
var name = c.getName() ~ "[" ~ c.getIndex() ~ "]";
|
||||
copy(src.getNode(name), dest.getNode(name, 1), attr);
|
||||
}
|
||||
var type = src.getType();
|
||||
var val = src.getValue();
|
||||
if(type == "ALIAS" or type == "NONE") return;
|
||||
elsif(type == "BOOL") dest.setBoolValue(val);
|
||||
elsif(type == "INT" or type == "LONG") dest.setIntValue(val);
|
||||
elsif(type == "FLOAT" or type == "DOUBLE") dest.setDoubleValue(val);
|
||||
else dest.setValue(val);
|
||||
if(attr) dest.setAttribute(src.getAttribute());
|
||||
}
|
||||
|
||||
##
|
||||
# Utility. Turns any ghosts it finds (either solo, or in an
|
||||
# array) into Node objects.
|
||||
#
|
||||
var wrap = func(node) {
|
||||
var argtype = typeof(node);
|
||||
if(argtype == "ghost") {
|
||||
return wrapNode(node);
|
||||
} elsif(argtype == "vector") {
|
||||
var v = node;
|
||||
var n = size(v);
|
||||
for(var i=0; i<n; i+=1) { v[i] = wrapNode(v[i]); }
|
||||
return v;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
##
|
||||
# Utility. Returns a new object with its superclass/parent set to the
|
||||
# Node object and its _g (ghost) field set to the specified object.
|
||||
# Nasal's literal syntax can be pleasingly terse. I like that. :)
|
||||
#
|
||||
var wrapNode = func(node) { { parents : [Node], _g : node } }
|
||||
|
||||
##
|
||||
# Global property tree. Set once at initialization. Is that OK?
|
||||
# Does anything ever call globals.set_props() from C++? May need to
|
||||
# turn this into a function if so.
|
||||
#
|
||||
var globals = wrapNode(_globals());
|
||||
|
||||
##
|
||||
# Shortcut for props.globals.getNode().
|
||||
#
|
||||
var getNode = func return call(props.globals.getNode, arg, props.globals);
|
||||
|
||||
##
|
||||
# Sets all indexed property children to a single value. arg[0]
|
||||
# specifies a property name (e.g. /controls/engines/engine), arg[1] a
|
||||
# path under each node of that name to set (e.g. "throttle"), arg[2]
|
||||
# is the value.
|
||||
#
|
||||
var setAll = func(base, child, value) {
|
||||
var node = props.globals.getNode(base);
|
||||
if(node == nil) return;
|
||||
var name = node.getName();
|
||||
node = node.getParent();
|
||||
if(node == nil) return;
|
||||
var children = node.getChildren();
|
||||
foreach(var c; children)
|
||||
if(c.getName() == name)
|
||||
c.getNode(child, 1).setValue(value);
|
||||
}
|
||||
|
||||
##
|
||||
# Turns about anything into a list of props.Nodes, including ghosts,
|
||||
# path strings, vectors or hashes containing, as well as functions
|
||||
# returning any of the former and in arbitrary nesting. This is meant
|
||||
# to be used in functions whose main purpose is to handle collections
|
||||
# of properties.
|
||||
#
|
||||
var nodeList = func {
|
||||
var list = [];
|
||||
foreach(var a; arg) {
|
||||
var t = typeof(a);
|
||||
if(isa(a, Node))
|
||||
append(list, a);
|
||||
elsif(t == "scalar")
|
||||
append(list, props.globals.getNode(a, 1));
|
||||
elsif(t == "vector")
|
||||
foreach(var i; a)
|
||||
list ~= nodeList(i);
|
||||
elsif(t == "hash")
|
||||
foreach(var i; keys(a))
|
||||
list ~= nodeList(a[i]);
|
||||
elsif(t == "func")
|
||||
list ~= nodeList(a());
|
||||
elsif(t == "ghost" and ghosttype(a) == "prop")
|
||||
append(list, wrapNode(a));
|
||||
else
|
||||
die("nodeList: invalid nil property");
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
##
|
||||
# Compiles a <condition> property branch according to the rules
|
||||
# set out in $FG_ROOT/Docs/README.conditions into a Condition object.
|
||||
# The 'test' method of the returend object can be used to evaluate
|
||||
# the condition.
|
||||
# The function returns nil on error.
|
||||
#
|
||||
var compileCondition = func(p) {
|
||||
if(p == nil) return nil;
|
||||
if(!isa(p, Node)) p = props.globals.getNode(p);
|
||||
return _createCondition(p._g);
|
||||
}
|
||||
|
||||
##
|
||||
# Evaluates a <condition> property branch according to the rules
|
||||
# set out in $FG_ROOT/Docs/README.conditions. Undefined conditions
|
||||
# and a nil argument are "true". The function dumps the condition
|
||||
# branch and returns nil on error.
|
||||
#
|
||||
var condition = func(p) {
|
||||
if(p == nil) return 1;
|
||||
if(!isa(p, Node)) p = props.globals.getNode(p);
|
||||
return _cond_and(p)
|
||||
}
|
||||
|
||||
var _cond_and = func(p) {
|
||||
foreach(var c; p.getChildren())
|
||||
if(!_cond(c)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
var _cond_or = func(p) {
|
||||
foreach(var c; p.getChildren())
|
||||
if(_cond(c)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
var _cond = func(p) {
|
||||
var n = p.getName();
|
||||
if(n == "or") return _cond_or(p);
|
||||
if(n == "and") return _cond_and(p);
|
||||
if(n == "not") return !_cond_and(p);
|
||||
if(n == "equals") return _cond_cmp(p, 0);
|
||||
if(n == "not-equals") return !_cond_cmp(p, 0);
|
||||
if(n == "less-than") return _cond_cmp(p, -1);
|
||||
if(n == "greater-than") return _cond_cmp(p, 1);
|
||||
if(n == "less-than-equals") return !_cond_cmp(p, 1);
|
||||
if(n == "greater-than-equals") return !_cond_cmp(p, -1);
|
||||
if(n == "property") return !!getprop(p.getValue());
|
||||
printlog("alert", "condition: invalid operator ", n);
|
||||
dump(p);
|
||||
return nil;
|
||||
}
|
||||
|
||||
var _cond_cmp = func(p, op) {
|
||||
var left = p.getChild("property", 0, 0);
|
||||
if(left != nil) { left = getprop(left.getValue()); }
|
||||
else {
|
||||
printlog("alert", "condition: no left value");
|
||||
dump(p);
|
||||
return nil;
|
||||
}
|
||||
var right = p.getChild("property", 1, 0);
|
||||
if(right != nil) { right = getprop(right.getValue()); }
|
||||
else {
|
||||
right = p.getChild("value", 0, 0);
|
||||
if(right != nil) { right = right.getValue(); }
|
||||
else {
|
||||
printlog("alert", "condition: no right value");
|
||||
dump(p);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
if(left == nil or right == nil) {
|
||||
printlog("alert", "condition: comparing with nil");
|
||||
dump(p);
|
||||
return nil;
|
||||
}
|
||||
if(op < 0) return left < right;
|
||||
if(op > 0) return left > right;
|
||||
return left == right;
|
||||
}
|
||||
|
||||
##
|
||||
# Runs <binding> as described in $FG_ROOT/Docs/README.commands using
|
||||
# a given module by default, and returns 1 if fgcommand() succeeded,
|
||||
# or 0 otherwise. The module name won't override a <module> defined
|
||||
# in the binding.
|
||||
#
|
||||
var runBinding = func(node, module = nil) {
|
||||
if(module != nil and node.getNode("module") == nil)
|
||||
node.getNode("module", 1).setValue(module);
|
||||
var cmd = node.getNode("command", 1).getValue() or "null";
|
||||
condition(node.getNode("condition")) ? fgcommand(cmd, node) : 0;
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Property / object update manager
|
||||
#
|
||||
# - Manage updates when a value has changed more than a predetermined amount.
|
||||
# This class is designed to make updating displays (e.g. canvas), or
|
||||
# performing actions based on a property (or value in a hash) changing
|
||||
# by more than the preset amount.
|
||||
# This can make a significant improvement to performance compared to simply
|
||||
# redrawing a canvas in an update loop.
|
||||
# - Author : Richard Harrison (rjh@zaretto.com)
|
||||
#---------------------------------------------------------------------------*/
|
||||
|
||||
#example usage:
|
||||
# this is using the hashlist (which works well with an Emesary notification)
|
||||
# basically when the method is called it will call each section (in the lambda)
|
||||
# when the value changes by more than the amount specified as the second parameter.
|
||||
# It is possible to reference multiple elements from the hashlist in each FromHashList; if either
|
||||
# one changes then it will result in the lambda being called.
|
||||
#
|
||||
# obj.update_items = [
|
||||
# UpdateManager.FromHashList(["VV_x","VV_y"], 0.01, func(val)
|
||||
# {
|
||||
# obj.VV.setTranslation (val.VV_x, val.VV_y + pitch_offset);
|
||||
# }),
|
||||
# UpdateManager.FromHashList(["pitch","roll"], 0.025, func(hdp)
|
||||
# {
|
||||
# obj.ladder.setTranslation (0.0, hdp.pitch * pitch_factor+pitch_offset);
|
||||
# obj.ladder.setCenter (118,830 - hdp.pitch * pitch_factor-pitch_offset);
|
||||
# obj.ladder.setRotation (-hdp.roll_rad);
|
||||
# obj.roll_pointer.setRotation (hdp.roll_rad);
|
||||
# }),
|
||||
# props.UpdateManager.FromProperty("velocities/airspeed-kt", 0.01, func(val)
|
||||
# {
|
||||
# obj.ias_range.setTranslation(0, val * ias_range_factor);
|
||||
# }),
|
||||
# props.UpdateManager.FromPropertyHashList(["orientation/alpha-indicated-deg", "orientation/side-slip-deg"], 0.1, func(val)
|
||||
# {
|
||||
# obj.VV_x = val.property["orientation/side-slip-deg"].getValue()*10; # adjust for view
|
||||
# obj.VV_y = val.property["orientation/alpha-indicated-deg"].getValue()*10; # adjust for view
|
||||
# obj.VV.setTranslation (obj.VV_x, obj.VV_y);
|
||||
# }),
|
||||
# ]
|
||||
#
|
||||
#==== the update loop then becomes ======
|
||||
#
|
||||
# foreach(var update_item; me.update_items)
|
||||
# {
|
||||
# # hdp is a data provider that can be used as the hashlist for the property
|
||||
# # update from hash methods.
|
||||
# update_item.update(hdp);
|
||||
# }
|
||||
#
|
||||
var UpdateManager =
|
||||
{
|
||||
_updateProperty : func(_property)
|
||||
{
|
||||
},
|
||||
FromProperty : func(_propname, _delta, _changed_method)
|
||||
{
|
||||
var obj = {parents : [UpdateManager] };
|
||||
obj.propname = _propname;
|
||||
obj.property = props.globals.getNode(_propname);
|
||||
obj.delta = _delta;
|
||||
obj.curval = obj.property.getValue();
|
||||
obj.lastval = obj.curval;
|
||||
obj.changed = _changed_method;
|
||||
obj.update = func(obj)
|
||||
{
|
||||
me.curval = me.property.getValue();
|
||||
if (me.curval != nil)
|
||||
{
|
||||
me.localType = me.property.getType();
|
||||
if (me.localType == "INT" or me.localType == "LONG" or me.localType == "FLOAT" or me.localType == "DOUBLE")
|
||||
{
|
||||
if(me.lastval == nil or math.abs(me.lastval - me.curval) >= me.delta)
|
||||
{
|
||||
me.lastval = me.curval;
|
||||
me.changed(me.curval);
|
||||
}
|
||||
}
|
||||
else if(me.lastval == nil or me.lastval != me.curval)
|
||||
{
|
||||
me.lastval = me.curval;
|
||||
me.changed(me.curval);
|
||||
}
|
||||
}
|
||||
};
|
||||
obj.update(obj);
|
||||
return obj;
|
||||
},
|
||||
|
||||
IsNumeric : func(hashkey)
|
||||
{
|
||||
me.localType = me.property[hashkey].getType();
|
||||
if (me.localType == "UNSPECIFIED") {
|
||||
print("UpdateManager: warning ",hashkey," is ",ty, " excluding from update");
|
||||
me.property[hashkey] = nil;
|
||||
}
|
||||
if (me.localType == "INT" or me.localType == "LONG" or me.localType == "FLOAT" or me.localType == "DOUBLE")
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
},
|
||||
|
||||
FromPropertyHashList : func(_keylist, _delta, _changed_method)
|
||||
{
|
||||
var obj = {parents : [UpdateManager] };
|
||||
obj.hashkeylist = _keylist;
|
||||
obj.delta = _delta;
|
||||
obj.lastval = {};
|
||||
obj.hashkey = nil;
|
||||
obj.changed = _changed_method;
|
||||
obj.needs_update = 0;
|
||||
obj.property = {};
|
||||
obj.is_numeric = {};
|
||||
foreach (hashkey; obj.hashkeylist) {
|
||||
obj.property[hashkey] = props.globals.getNode(hashkey);
|
||||
obj.lastval[hashkey] = nil;
|
||||
# var ty = obj.property[hashkey].getType();
|
||||
# if (ty == "INT" or ty == "LONG" or ty == "FLOAT" or ty == "DOUBLE") {
|
||||
# obj.is_numeric[hashkey] = 1;
|
||||
# } else
|
||||
# obj.is_numeric[hashkey] = 0;
|
||||
#print("create: ", hashkey," ", ty, " isnum=",obj.is_numeric[hashkey]);
|
||||
# if (ty == "UNSPECIFIED")
|
||||
# print("UpdateManager: warning ",hashkey," is ",ty);
|
||||
}
|
||||
obj.update = func(obj)
|
||||
{
|
||||
if (me.lastval == nil)
|
||||
me.needs_update = 1;
|
||||
else {
|
||||
me.needs_update = 0;
|
||||
|
||||
foreach (hashkey; me.hashkeylist) {
|
||||
if (me.property[hashkey] != nil) {
|
||||
me.valIsNumeric = me.IsNumeric(hashkey);
|
||||
|
||||
if (me.lastval[hashkey] == nil
|
||||
or (me.valIsNumeric and (math.abs(me.lastval[hashkey] - me.property[hashkey].getValue()) >= me.delta))
|
||||
or (!me.valIsNumeric and (me.lastval[hashkey] != me.property[hashkey].getValue()))) {
|
||||
me.needs_update = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (me.needs_update) {
|
||||
me.changed(me);
|
||||
foreach (hashkey; me.hashkeylist) {
|
||||
me.lastval[hashkey] = me.property[hashkey].getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
return obj;
|
||||
},
|
||||
FromHashValue : func(_key, _delta, _changed_method)
|
||||
{
|
||||
var obj = {parents : [UpdateManager] };
|
||||
obj.hashkey = _key;
|
||||
obj.delta = _delta;
|
||||
obj.isnum = _delta != nil;
|
||||
obj.curval = nil;
|
||||
obj.lastval = nil;
|
||||
obj.changed = _changed_method;
|
||||
obj.update = func(obj)
|
||||
{
|
||||
me.curval = obj[me.hashkey];
|
||||
if (me.curval != nil) {
|
||||
if (me.isnum) {
|
||||
me.curval = num(me.curval);
|
||||
if (me.lastval == nil or math.abs(me.lastval - me.curval) >= me.delta) {
|
||||
me.lastval = me.curval;
|
||||
me.changed(me.curval);
|
||||
}
|
||||
} else {
|
||||
if (me.lastval == nil or me.lastval != me.curval) {
|
||||
me.lastval = me.curval;
|
||||
me.changed(me.curval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
||||
return obj;
|
||||
},
|
||||
FromHashList : func(_keylist, _delta, _changed_method)
|
||||
{
|
||||
var obj = {parents : [UpdateManager] };
|
||||
obj.hashkeylist = _keylist;
|
||||
obj.delta = _delta;
|
||||
obj.lastval = {};
|
||||
obj.hashkey = nil;
|
||||
obj.changed = _changed_method;
|
||||
obj.needs_update = 0;
|
||||
obj.isnum = _delta != nil;
|
||||
obj.update = func(obj)
|
||||
{
|
||||
if (me.lastval == nil)
|
||||
me.needs_update = 1;
|
||||
else
|
||||
me.needs_update = 0;
|
||||
|
||||
if (obj != nil or me.lastval == nil) {
|
||||
foreach (hashkey; me.hashkeylist) {
|
||||
if (me.isnum) {
|
||||
if (me.lastval[hashkey] == nil or math.abs(me.lastval[hashkey] - obj[hashkey]) >= me.delta) {
|
||||
me.needs_update = 1;
|
||||
break;
|
||||
}
|
||||
} elsif (me.lastval[hashkey] == nil or me.lastval[hashkey] != obj[hashkey]) {
|
||||
me.needs_update = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (me.needs_update) {
|
||||
me.changed(obj);
|
||||
foreach (hashkey; me.hashkeylist) {
|
||||
me.lastval[hashkey] = obj[hashkey];
|
||||
}
|
||||
}
|
||||
};
|
||||
return obj;
|
||||
},
|
||||
};
|
||||
35
test/queue.nas
Normal file
35
test/queue.nas
Normal file
@@ -0,0 +1,35 @@
|
||||
# lib queue.nas
|
||||
var block_alloc=func()
|
||||
{
|
||||
return {elem:nil,next:nil};
|
||||
}
|
||||
var new_queue=func()
|
||||
{
|
||||
return {next:nil};
|
||||
}
|
||||
var queue_push=func(queue,elem)
|
||||
{
|
||||
var tmp=queue;
|
||||
while(tmp.next!=nil)
|
||||
tmp=tmp.next;
|
||||
tmp.next=block_alloc();
|
||||
tmp.next.elem=elem;
|
||||
}
|
||||
var queue_pop=func(queue)
|
||||
{
|
||||
var tmp=queue.next;
|
||||
if(tmp!=nil)
|
||||
queue.next=tmp.next;
|
||||
return;
|
||||
}
|
||||
var queue_front=func(queue)
|
||||
{
|
||||
var tmp=queue.next;
|
||||
if(tmp!=nil)
|
||||
return tmp.elem;
|
||||
return nil;
|
||||
}
|
||||
var queue_empty=func(queue)
|
||||
{
|
||||
return queue.next==nil;
|
||||
}
|
||||
126
test/scalar.nas
Normal file
126
test/scalar.nas
Normal file
@@ -0,0 +1,126 @@
|
||||
# basic type
|
||||
nil;
|
||||
2147483647;
|
||||
0x7fffffff;
|
||||
0xdeadbeef;
|
||||
0o70120327;
|
||||
"hello world!";
|
||||
'hello world!';
|
||||
-12;
|
||||
!0;
|
||||
-((30));
|
||||
[];
|
||||
{};
|
||||
[0,1,2,3,4,5][2]; # 2
|
||||
[0,1,2,3,4,5,6,7,8,9,10][0,2,4:7,9];
|
||||
[0,1,2,3,4,5,6,7,8,9,10,][0,2,4:7,9];
|
||||
([0,1,2,3,4])[2]; # 2
|
||||
(([0,1,2,3]))[2]; # 2
|
||||
[0,1,2,3,4,5][5,4,3,2+1][0:2][0]; # 5
|
||||
{str:"hello"}.str; # "hello"
|
||||
{str:"hello"}["str"]; # "hello"
|
||||
{"str":"hello\"\"\n"}["str"]; # "hello"
|
||||
20? 1:0;
|
||||
|
||||
# normal scalar
|
||||
var number_1=1;
|
||||
var number_2=0xdeadbeef;
|
||||
var number_3=0x13702;
|
||||
var number_4=0.12341490239423;
|
||||
var string_1="hello";
|
||||
var string_2='hello';
|
||||
var string_3=number_1? 'yes':'no'; # yes
|
||||
|
||||
# vector
|
||||
var vector_1=[];
|
||||
var vector_2=[0,1,2,"str",number_1,vector_1];
|
||||
var vector_3=vector_2[-3,-1];
|
||||
var vector_4=vector_2[0:3];
|
||||
var vector_5=vector_2[3:];
|
||||
|
||||
# hash
|
||||
var hash_1={};
|
||||
var hash_2={str1:'str1', str2:'str2', num1:0x7fffffff};
|
||||
var hash_3={
|
||||
"member_1":1,
|
||||
"member_2":2,
|
||||
"member_3":3,
|
||||
};
|
||||
var hash_4={
|
||||
mem_1:hash_1,
|
||||
mem_2:hash_2.num1, # also this can be written as hash_2["num1"]
|
||||
mem_3:hash_3["member_1"]
|
||||
};
|
||||
|
||||
# function
|
||||
var func_1=func(){return 1;}
|
||||
var prt=func(x){print(x);return nil;}
|
||||
var func_with_dynamic_id=func(a,b,c,d...){return [a,b,c,d];}
|
||||
var func_with_lack_para=func(a,b,c=1,d=2){return a+b+c+d;}
|
||||
var func_with_func_para=func(a,f){return f(a);}
|
||||
|
||||
func_with_lack_para(a:1, b:2, c:3, d:4);
|
||||
func_with_lack_para(b:1, c:3, a:4, d:1);
|
||||
func_with_func_para(f:func prt,a:1);
|
||||
func_with_func_para(func func_1(),func(x){return x;});
|
||||
func_with_func_para(func_1(),func_1);
|
||||
prt(func func_1());
|
||||
var test_func_ret_number_1=func func_1(); # 1
|
||||
var test_func_ret_number_2=func_1(); # 1
|
||||
|
||||
var source={
|
||||
member_1: func func_1(), # this will get a number
|
||||
member_2: func {return 2.71828;} # this will get a function
|
||||
};
|
||||
print(source['member_2']());
|
||||
print(source.member_2());
|
||||
|
||||
var test_func=func{return 1;}
|
||||
print(func test_func()); # 1
|
||||
print(test_func()); # 1
|
||||
print(func test_func); # nothing
|
||||
print(test_func); # nothing
|
||||
print(([0,1,2,3])[1]); # 1
|
||||
print(({str:"what?"})["str"]); # what?
|
||||
print(({str:"what?"}).str); # what?
|
||||
|
||||
# lambda
|
||||
(func(x){return x>0? x:0;})(12);
|
||||
(func{print("hello world");})();
|
||||
(((func(x){return 1.0/math.exp(x);})))(0);
|
||||
|
||||
# flexible definition & assignment
|
||||
var (r,g,b)=[0x00,0x10,0xff];
|
||||
(var r,g,b)=[0x00,0x10,0xff];
|
||||
var color=[0x00,0x10,0xff];
|
||||
var (r,g,b)=color;
|
||||
(var r,g,b)=color;
|
||||
(r,g,b)=(b,g,r);
|
||||
(number_1,number_2)=(number_2,number_1);
|
||||
var (swap_a,swap_b)=(0x1,0x80);
|
||||
(swap_a,swap_b)=(swap_b,swap_a);
|
||||
# ((swap_a),(swap_b))=(swap_b,swap_a) is wrong
|
||||
# anything that use multi_assignment must not have curve around them
|
||||
var multi_assign_1=[0,1,2,3,4];
|
||||
var multi_assign_2=[10,9,8,7];
|
||||
(multi_assign_1[1],multi_assign_2[0])=(multi_assign_1[2],multi_assign_2[1]);
|
||||
|
||||
# calculation
|
||||
1+1;
|
||||
1+1-2+3-4+5-6;
|
||||
1+1*8-9/3;
|
||||
1*-1;
|
||||
1*(1+2*(3+4*(5+6*(7+8*(9+10/(1+1))))));
|
||||
((-1*2+9))/7-1;
|
||||
((({num:2})))["num"]*2*2*2;
|
||||
((((([0,1,2])[0:2]))[0:2]))[1]-1;
|
||||
(((((((((((((((((((1+1+2+3+5)+8))+13)))+21))))+34)))))+55))))*89;
|
||||
number_1*(number_2+number_3)/90-number_4;
|
||||
(func test_func)()-1;
|
||||
hash_3.member_3+(func {return {what:"i don't tell you.",case_small:80,case_large:100}})()["case_large"]/10;
|
||||
-1*10+5 or 10-10;
|
||||
nil and 1+7*8;
|
||||
(number_1 or number_2) and (number_3 or number_4-number_4*1);
|
||||
[0,1,4,3,2][4]*2-4+1*2*2*2*2*2/8;
|
||||
{num:0}.num or {what_is_the_secret_of_universe:42}["what_is_the_secret_of_universe"];
|
||||
"123"~"456"-123456*2/2;
|
||||
62
test/scope.nas
Normal file
62
test/scope.nas
Normal file
@@ -0,0 +1,62 @@
|
||||
var global_value=0;
|
||||
var global_hash=
|
||||
{
|
||||
var1:1,
|
||||
var2:2,
|
||||
var3:func(){return me.var2;}
|
||||
};
|
||||
print(global_value);
|
||||
print(global_hash.var3());
|
||||
|
||||
var func1=func()
|
||||
{
|
||||
global_value=1;
|
||||
print(global_value);
|
||||
var closure_value=1;
|
||||
var temp_value=1;
|
||||
print(temp_value);
|
||||
return func{return closure_value;};
|
||||
}
|
||||
|
||||
var func2=func()
|
||||
{
|
||||
for(var temp_value=0;temp_value<100;temp_value+=1)
|
||||
{
|
||||
if(temp_value<10)
|
||||
print(temp_value,"< 10");
|
||||
elsif(10<=temp_value and temp_value<50)
|
||||
print(temp_value,"< 50");
|
||||
temp_value=10;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var func3=func()
|
||||
{
|
||||
var fake_closure_value=1;
|
||||
return func()
|
||||
{
|
||||
var fake_closure_value=2;
|
||||
return fake_closure_value;
|
||||
};
|
||||
}
|
||||
|
||||
func1()();
|
||||
func2();
|
||||
func3()();
|
||||
|
||||
if(!global_value)
|
||||
{
|
||||
var temp_value=1;
|
||||
if(temp_value)
|
||||
{
|
||||
var temp_value=2;
|
||||
if(temp_value>=1)
|
||||
{
|
||||
var temp_value=3;
|
||||
print(temp_value);
|
||||
}
|
||||
print(temp_value);
|
||||
}
|
||||
print(temp_value);
|
||||
}
|
||||
24
test/special.nas
Normal file
24
test/special.nas
Normal file
@@ -0,0 +1,24 @@
|
||||
var hash={str:'hello',f:func{return me.str;}};
|
||||
var tmp_f=hash.f;
|
||||
hash=1;
|
||||
print(tmp_f());
|
||||
# undefined symbol 'me'
|
||||
# this means that
|
||||
# when generating local_scope for function f,
|
||||
# nasal_gc will not count 'me' as one reference of this hash
|
||||
|
||||
var h1={str:'hello',f:func{return me.str;}};
|
||||
var h2={str:'world',f:func{return nil;}};
|
||||
h2.f=h1.f;
|
||||
print(h2.f());
|
||||
# print 'world'
|
||||
# this means that 'me' in hash's functions
|
||||
# only points to the hash this function belongs to
|
||||
|
||||
var f1=func(){print(1);return 1;}
|
||||
var f2=func(){print(2);return 0;}
|
||||
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
|
||||
34
test/stack.nas
Normal file
34
test/stack.nas
Normal file
@@ -0,0 +1,34 @@
|
||||
# lib stack.nas
|
||||
var block_alloc=func()
|
||||
{
|
||||
return {elem:nil,next:nil};
|
||||
}
|
||||
var new_stack=func()
|
||||
{
|
||||
return {next:nil};
|
||||
}
|
||||
var stack_push=func(stack,elem)
|
||||
{
|
||||
var tmp=stack.next;
|
||||
stack.next=block_alloc();
|
||||
stack.next.elem=elem;
|
||||
stack.next.next=tmp;
|
||||
}
|
||||
var stack_pop=func(stack)
|
||||
{
|
||||
var tmp=stack.next;
|
||||
if(tmp!=nil)
|
||||
stack.next=tmp.next;
|
||||
return;
|
||||
}
|
||||
var stack_top=func(stack)
|
||||
{
|
||||
var tmp=stack.next;
|
||||
if(tmp!=nil)
|
||||
return tmp.elem;
|
||||
return nil;
|
||||
}
|
||||
var stack_empty=func(stack)
|
||||
{
|
||||
return stack.next==nil;
|
||||
}
|
||||
5
test/string.nas
Normal file
5
test/string.nas
Normal file
@@ -0,0 +1,5 @@
|
||||
import("lib.nas");
|
||||
var filename="";
|
||||
|
||||
filename=input();
|
||||
print(filename[0]);
|
||||
Reference in New Issue
Block a user