aardio教程一) 基础语法-上

前言

想开发一些小工具,所以想系统性的学习一遍aardio,之前都是哪里不会搜哪里,顺便写些教程。我的主要语言是Python,所以会以Python作为对比来加深印象。

aardio的基础语法和JavaScript基本类似,如果你学过JavaScript,aardio很容易上手。下面的文档来自官方文档 [1]

问题搜索途径

基础语法看:https://bbs.aardio.com/doc/reference/

一些库的使用,获取文档有以下途径:

  1. aardio官方论坛(https://bbs.aardio.com),我一般用谷歌搜索 site:bbs.aardio.com 搜索内容
  2. aardio官方公众号
  3. 打开编辑器开始页的话有开发指南和文档资源,右侧有官方资讯,刚入门都可以看一下。里面的库函数文档我经常用
  4. 写一个函数的时候右键转到定义,库代码下面一般都有注释怎么用
  5. 用vscode打开整个aardio软件目录,搜索你不知道怎么用的库,看看官方是怎么使用的,这个我用的最多
  6. aardio相关的第三方论坛:https://aardio.online/thread-20.htm

语法

标识符

变量标识符的定义和Python基本一样,语法如下:

  • 字母(区分大小写)、数字和下划线,也可以用中文
  • 数字不能作为变量首个字符

与Python不同的点:

  • 除了单个下划线_,其他下划线开头的为常量,定义后无法被修改
  • 可以以$符开头
  • 包含中文时,前面不能有字符和数字

关键字

- -
var 用于定义局部变量 def 用于定义关键字
and not or 逻辑运算符 begin end 用于包含语句块
if else elseif 用于条件判断语句 for in 用于循环语句
select case 用于条件判断语句 try catch 用于捕获异常
break continue 循环中断语句 function 用于创建函数
namespace 用于创建或打开名字空间 import 用于引用库
this 用于在类内部表示当前实例对象 global 用于表示全局名字空间
owner 用于表示调用函数的主体对象 while do 用于循环语句
null 用于表示空值 false true 用于表示布尔值
class ctor 用于创建类 return 用于函数中返回值
with 用于打开名字空间 self 用于表示当前名字空间

你如果闲的无聊的话,也可以使用def自定义关键词,比如:

def 如果 = if
def 否则 = else
def 否则是 = elseif
def 名字空间= namespace
def 循环 = while

io.open();

如果 1== 1 {
    io.print(" 1等于1 ")
}
否则{
    io.print(" 1不等于1 ")
}

改个名字和图标,一款新的中文编程语言就写好了

分隔符和注释符

分隔每条语句可以用换行或者分号, 一下三种方法都可以:
var a = 1; var b = 2;

var a, b = 1, 2;

# 后面的分号可写可不写,我一般都写上
var a = 1
var b = 2

注释则是使用///**/,也可以使用多个/******/,只需要前面和后面的数量对应上

操作符

算术运算符 + - * / ** %
按位运算符 ~ 取反 & ` ` 或 ^ 异或 << 左移
等式运算符 == !=
逻辑运算符 ! not ` or :` && and ?
关系运算符 > < >= <=
连接运算符 ++
取长运算符 #
全局变量定义 ::
成员操作符 . [] [[]]
包含操作符 $
  • 字符串之间使用关系运算符时,是从第一个字符开始比较,这个和Python也是一样的
  • ++并不是c语言里面的自增,而是用于字符串和字符串拼接,或者字符串和数值拼接。例如: 1 ++ "2" == "12",也可以省略成1+"2"
  • 取长运算符用于获取字符串和数组长度,如果是对象则调用_len元方法
  • 在变量名前面加::表示为全局常量,比如::Kernel32 := raw.loadDll("Kernel32.dll");,可以避免重复加载dll
  • 成员操作符.和[]基本可以混用,除非成员名称不符合aardio命令规定则使用[]
  • [[]]一般是在元方法中使用,它不会调用元方法,可以避免无限递归
  • 路径字符串前加$符表示内嵌该文件到编译后的exe中

逻辑运算符

||or:再使用上基本没有区别,大部分情况下可以互相替换。

  • 逻辑与和逻辑或运算符就能组成类似三元运算符的效果 true ? 1 : 0
  • a := 1等同于a = a : 1,可以用于避免重复赋值
  • a ?= f(a)等同于a = a ? f(a),可以只当a不为null执行f(a)
  • 也有像Python一样的用逻辑运算符做条件取值的操作,比如a = 1 or 2b = 0 or 3。语法和意思也和Python是一样的

按位无符号右移

a >>> n 将数值a按位向右移动n位(如果n大于等于32,则为n对32取模结果的位数) ,不保留符号位(负数不保持最高位为1,因此右移后会变成正数)

实际用途:

可以通过右移 0 位将有符号数强制转换为无符号数。例如 -1 >>> 0 的值为 0xFFFFFFFF , 其作用等价于 raw.convert( {int value = -1},{INT value}).value。

不声明调用静态 API 默认会返回 32位有符号整数,如果原 API 返回的是 32位无符号整数,那么只要简单的将返回值 >>> 0 就可以得到原来的无符号数值了

这里有一点很重要: 内存里的数据都是0和1,它是什么值只取决于你以什么类型读取它

等式运算符

基础数据类型会判断值是否相等,而非基本类型则是判断对象是否相等或者调用_eq元方法判断

元方法类似Python的魔法方法,可以重载对象的符号运算,比如_eq重载==

0, nullfalse 相等,其他类型都与true想等

跟数值类型比较时:

  • 字符串会自动转为数值类型再做比较,空字符串""转为0,空白字符\r\n\t也是转为0
  • 如果是对象,则是调用_tonumber元方法转数值
表达式 结果
"123"==123 true
"abc"==123 false
""==0 true
'\r\n\t '==0 true
null==0 false

还有一个恒等判断的符号===!==,它不会调用_eq元方法,直接判断类型和数值都相等

运算符优先级

这个东西没必要记,有疑问时加括号即可。遇到别人的代码有疑问,可以运行测试下

基础数据类型

类型 举例值 说明
type.null null
type.boolean 布尔值
type.number 数值 默认为64位浮点数
type.string 字符串 字符串和Python也基本一样,utf-8编码
type.buffer raw.buffer 可用于接收c语言char*数据
type.pointer 指针 接收dll返回的指针数据,或者使用topointer(obj)
type.table aardio中的数组、字典等复杂类型
type.function 函数 function创建的函数
type.cdata 内核对象 一般不用关心
type.fiber 纤程 没用过
type.class class关键词创建的类

null

任何没有定义或赋值的变量默认都是null。如果函数不传参数,默认传过去的也是null。

import console; 
console.dump(a);
console.pause(true);
import console; 
function f(a){
	console.dump(a);
}
f()
console.pause(true);

数值类型

  • 2#11表示二进制数,8#11表示八进制数,16#A表示十六进制数,也可以表示为0xA
  • 2e+20(2x10**20)表示科学计数法, +仅表示指数的正负,可加可不加
  • 可以用_来分隔数值,111_222等同于111222

字符串

aardio中定义的字符串都是utf-8编码

string.fromUnicode(s)string.toUnicode(s)可以做utf-8 <=> utf-16的转换,Windows上使用的Unicode编码一般就是指的utf-16,两个函数都可以指定第二个参数,代表目标编码的代码页,用于转换其他编码。

常用的代码页: 936(gb2312)、1200(utf-16 le)、1201(utf-16 be)、65001(utf-8)。所有代码页可以参考: 标准代码页(codepage)列表 [2]

Windows可以在cmd下使用chcp命令查看当前使用的代码页,一般情况下都是936。

定义字符串的话有四种方式: 双引号("")、单引号('')、反引号(``)和注释符(/**/)。其中双引号和反引号用法是一样的

都可以定义多行字符串:

a = "1
2";
b = '1
2';
c = /*1
2*/

不同点:

  • 只有单引号可以使用转义字符,例如'\n'表示换行。
  • 单引号的换行会被忽略,所以单引号表示换行时和c语言一样使用转义字符\n
  • 双引号的换行会被替换成\n
  • 注释符的换行会被替换成\r\n
  • 在双引号中可以使用两个双引号表示双引号本身,例如"1222""11111",则等同于'1222"11111'
  • 在单引号中\'表示单引号本身, 例如'1222\'11111',则等同于"1222'11111"
  • 'A'#表示这个字符的ASCII值,也就是65
  • 'UTF16字符串'u表示UTF-16 LE编码的字符串
  • 文件路径引号前加$符表示编译后将文件嵌入到exe中,加载dll时经常会用到

全局函数

Python中有strintprint 这些可以使用的全局函数,aardio中也内置了一些可以全局使用的函数。我觉得用不到的就不在下面列出来了

tostring

  • 将某个值转换为字符串,如果是对象则调用_tostring元方法。
  • 第二个参数可以指定进制,比如tostring(10, 16)返回0xA
  • 如果第一个参数是时间,则第二个参数可以指定格式化时间的字符串,比如tostring(time(), "%Y-%m-%d %H:%M:%S")

topointer

将参数转换为指针,这个函数我还没用过。到时候用的时候再看什么作用

tonumber

  • 将某个值转换为数值,如果是对象则调用_tonumber元方法。
  • 如果是指针则返回内存地址
  • 如果是字符串, 第二个参数可以指定进制,例如tonumber("0xA", 16)

注意: 这个函数会返回两个值,第一个是转换后的数值。第二个是转换使用的字符数。例如tonumber("12a"), 返回12和2.

一般会使用两个值接收var a, b = tonumber("12a")

invoke

invoke(被调用函数, owner, 参数1, 参数2)

调用指定函数,owner这个后面再提

call

call(被调用函数, owner, 参数)

调用指定函数,跟invoke基本类似

callex

callex(异常处理函数,被调用函数, owner, 参数)

当被调用函数代码出现异常时则调用异常处理函数

loadcode

加载编译代码,参数可以是代码字符串或者代码路径

loadcodex

加载编译和运行代码,参数可以是代码字符串或者代码路径

dumpcode

编译代码为二进制字节

sleep

同步阻塞休眠,和Python的time.sleep一样,单线程情况下会卡住界面。界面中应使用win.delay

type

用于获取对象的数据类型,一般使用type(obj) == type.string来判断对象是不是字符串,所有类型请看基础语法中的基本数据类型

eval

运行aardio代码,并返回表达式的值

error

主动抛出异常

参考

  • [1] aardio官方文档: https://bbs.aardio.com/doc/reference/
  • [2] 标准代码页(codepage)列表: https://blog.csdn.net/jianggujin/article/details/80325461
  • Python所有全局函数: https://mp.weixin.qq.com/s/PA0lsojc-zkZ4eltj8P6Kg

本文由博客一文多发平台 OpenWrite 发布!

热门相关:恭喜我的前任   蛇之战   脱下衣服的漂亮姐姐   失衡凶间之恶念之最粤语   妈妈和女儿的性爱减肥法