update & bug fixed

This commit is contained in:
Valk Richard Li 2020-11-03 19:27:21 +08:00
parent 6f5143657e
commit 155ce6fc0d
23 changed files with 12704 additions and 41 deletions

View File

@ -208,12 +208,13 @@ 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);
@ -347,10 +348,10 @@ int nasal_runtime::builtin_rand(int local_scope_addr)
}
int nasal_runtime::builtin_id(int local_scope_addr)
{
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";
std::cout<<">> [runtime] builtin_id: cannot find \"thing\".\n";
++error;
return -1;
}

View File

@ -286,6 +286,8 @@ int nasal_hash::get_value_address(std::string key)
}
}
}
else
std::cout<<">> [runtime] cannot find hash member \""<<key<<"\".\n";
return ret_value_addr;
}
int nasal_hash::get_mem_address(std::string key)
@ -311,6 +313,15 @@ int nasal_hash::get_mem_address(std::string key)
}
}
}
else
{
int mem_addr=nasal_vm.mem_alloc();
int val_addr=nasal_vm.gc_alloc();
nasal_vm.gc_get(val_addr).set_type(vm_nil);
nasal_vm.mem_init(mem_addr,val_addr);
elems[key]=mem_addr;
ret_mem_addr=mem_addr;
}
return ret_mem_addr;
}
bool nasal_hash::check_contain(std::string key)

View File

@ -940,18 +940,18 @@ int nasal_runtime::call_function(nasal_ast& node,std::string func_name,int base_
int run_closure_addr=reference_of_func.get_closure_addr();
nasal_closure& run_closure=nasal_vm.gc_get(run_closure_addr).get_closure();
run_closure.add_scope();
// set self
if(func_name.length())
{
nasal_vm.add_reference(base_value_addr);
run_closure.add_new_value(func_name,base_value_addr);
}
// set hash.me
if(last_call_hash_addr>=0)
{
nasal_vm.add_reference(last_call_hash_addr);
run_closure.add_new_value("me",last_call_hash_addr);
}
else if(func_name.length())
{
// when hash.me does not exist,set self
nasal_vm.add_reference(base_value_addr);
run_closure.add_new_value(func_name,base_value_addr);
}
nasal_ast& argument_format=reference_of_func.get_arguments();
if(!node.get_children().size())
{

96
test/NasNeuron.nas Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

210
test/final.nas Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

195
test/json.nas Normal file
View 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;
}

167
test/lib.nas Normal file
View 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);
},
};

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,5 @@
import("lib.nas");
var filename="";
filename=input();
print(filename[0]);