Monkey v2.0版本已發佈。html
monkey v2.0python
增長了以下內容:git
short arrow(->)
支持(相似C#的lambda表達式)列表推導
和哈希推導
支持(相似python的列表推導)tuple
元祖類型10.upto(15)
vim, visual studio code, sublime Text 3, notepad++, emEditor
)詳細示例請看下面相關的說明。github
monkey正則表達式
若是你喜歡此項目,請點擊上面的連接,多多star,fork。 您的支持,是對個人鼓勵!sql
謝謝!數據庫
Monkey是一個用go語言寫的解析器. 語法借鑑了C, Ruby, Python和Perl.express
此項目是基於mayoms的項目 monkey,修改了其中的一些bug,同時增長了許多語言特性:json
string
模塊(可以正確處理utf8字符編碼)file
模塊(包含一些新方法).math
模塊sql(db)
模塊(可以正確的處理null
值)time
模塊sort
模塊os
模塊log
模塊net
模塊http
模塊filepath
模塊flag
模塊(用來處理命令行參數)json
模塊(json序列化和反序列化)fmt
模塊sync
模塊list
模塊linq
模塊(代碼來自linq並進行了相應的更改)csv
模塊template
模塊這個項目的目的主要有如下幾點:swift
可是,解析器的速度並非這個項目考慮的因素
下載本項目,運行./run.sh
你能夠以下方式使用REPL:
~ » monkey
Monkey programming language REPL
>>
複製代碼
或者運行一個monkey文件:
monkey path/to/file
複製代碼
Monkey僅支持單行註釋.
// an inline comment
# another inline comment
複製代碼
Monkey支持8種基本類型: String
, Int
, Float
, Bool
, Array
, Hash
, Tuple
和Nil
s1 = "hello, 黃" # strings are UTF-8 encoded
s2 = `hello, "world"` # raw string
i = 10 # int
f = 10.0 # float
b = true # bool
a = [1, "2"] # array
h = { "a"=>1, "b"=>2} # hash
t = (1,2,3) # tuple
n = nil
複製代碼
Monkey中,主要有10種類型的常量(字面量).
// Integer literals
i1 = 10
i2 = 20_000_000
i3 = 0x80 // hex
i4 = 0b10101 // binary
i5 = 0c127 // octal
// Float literals
f1 = 10.25
f2 = 1.02E3
f3 = 123_456.789_012
// String literals
s1 = "123"
s2 = "Hello world"
// Regular expression literals
r = /\d+/.match("12")
if (r) { prinln("regex matched!") }
// Array literals
a = [1+2, 3, 4, "5", 3]
// Hash literals
h = { "a"=>1, "b"=>2, "c"=>2}
//Tuple literals
t = (1, 2+3, "Hello", 5)
// Nil literal
n = nil
// Boolean literals
t = true
f = false
// Function literals
let f1 = add(x, y) { return x + y }
println(f1(1,2))
//short-arrow function literals
let f2 = (x, y) -> x + y
println(f2(1,2))
複製代碼
你可使用let
來聲明一個變量,或直接使用賦值的方式來聲明並賦值一個變量:variable=value
.
let a, b, c = 1, "hello world", [1,2,3]
d = 4
e = 5
姓="黃"
複製代碼
若是你不使用let
來給變量賦值,那麼你將不能使用多變量賦值。下面的語句是錯誤的:
//錯誤,多變量賦值必須使用let關鍵字
a, b, c = 1, "hello world", [1,2,3]
複製代碼
下面列出了monkey語言的保留字:
你可使用內置的方法:int()
, float()
, str()
, array()
, tuple
, hash
來進行不一樣類型之間的轉換.
let i = 0xa
let s = str(i) // result: "10"
let f = float(i) // result: 10
let a = array(i) // result: [10]
let t = tuple(i) // result: (10)
let h = hash(("key", "value")) // result: {"key"=>"value}
複製代碼
你能夠從一個數組建立一個tuple:
let t = tuple([10, 20]) //result:(10,20)
複製代碼
一樣的, 你也能夠從一個tuple建立一個數組:
let arr = array((10,20)) //result:[10,20]
複製代碼
你只能從數組或者tuple來建立一個hash:
//建立一個空的哈希
let h1 = hash() //same as h1 = {}
//從數組建立哈希
let h1 = hash([10, 20]) //result: {10 => 20}
let h2 = hash([10,20,30]) //result: {10 => 20, 30 => nil}
//從tuple建立哈希
let h3 = hash((10, 20)) //result: {10 => 20}
let h4 = hash((10,20,30)) //result: {10 => 20, 30 => nil}
複製代碼
qw
(Quote word)關鍵字qw
關鍵字相似perl的qw
關鍵字. 當你想使用不少的雙引號字符串時,qw
就是一個好幫手.
for str in qw<abc, def, ghi, jkl, mno> { //容許的成對操做符:'{}', '<>', '()'
println('str={str}')
}
newArr = qw(1,2,3.5) //注:這裏的newArr是一個字符串數組,不是一個整形數組.
fmt.printf("newArr=%v\n", newArr)
複製代碼
enum
關鍵字在mokey中,你可使用enum
來定義常量.
LogOption = enum {
Ldate = 1 << 0,
Ltime = 1 << 1,
Lmicroseconds = 1 << 2,
Llongfile = 1 << 3,
Lshortfile = 1 << 4,
LUTC = 1 << 5,
LstdFlags = 1 << 4 | 1 << 5
}
opt = LogOption.LstdFlags
println(opt)
//獲得`enum`的全部名稱
for s in LogOption.getNames() { //非排序(non-ordered)
println(s)
}
//獲得`enum`的全部值
for s in LogOption.getValues() { //非排序(non-ordered)
println(s)
}
// 獲得`enum`的一個特定的名字
println(LogOption.getName(LogOption.Lshortfile))
複製代碼
// if-else
let a, b = 10, 5
if (a > b) { // '()'可選, 可是'{}'必需要有
println("a > b")
}
elseif a == b { // 也可使用'elsif'和'elif'
println("a = b")
}
else {
println("a < b")
}
// for
i = 9
for { // 無限循環
i = i + 2
if (i > 20) { break }
println('i = {i}')
}
i = 0
for (i = 0; i < 5; i++) { // 相似c語言的for循環, '()'必需要有
if (i > 4) { break }
if (i == 2) { continue }
println('i is {i}')
}
for i in range(10) {
println('i = {i}')
}
a = [1,2,3,4]
for i in a where i % 2 != 0 {
println(i)
}
hs = {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6, "g"=>7}
for k, v in hs where v % 2 == 0 {
println('{k} : {v}')
}
for i in 1..5 {
println('i={i}')
}
for item in 10..20 where $_ % 2 == 0 { // $_ is the index
printf("idx=%d, item=%d\n", $_, item)
}
for c in "m".."a" {
println('c={c}')
}
for idx, v in "abcd" {
printf("idx=%d, v=%s\n", idx, v)
}
for idx, v in ["a", "b", "c", "d"] {
printf("idx=%d, v=%s\n", idx, v)
}
for item in ["a", "b", "c", "d"] where $_ % 2 == 0 { // $_ 是索引
printf("idx=%d, item=%s\n", $_, v)
}
//for循環是個表達式(expression),而不是一個語句(statement), 所以它可以被賦值給一個變量
let plus_one = for i in [1,2,3,4] { i + 1 }
fmt.println(plus_one)
// while
i = 10
while (i>3) {
i--
println('i={i}')
}
// do
i = 10
do {
i--
if (i==3) { break }
}
// try-catch-finally(僅支持throw一個string類型的變量)
let exceptStr = "SUMERROR"
try {
let th = 1 + 2
if (th == 3) { throw exceptStr }
}
catch "OTHERERROR" {
println("Catched OTHERERROR")
}
catch exceptStr {
println("Catched is SUMERROR")
}
catch {
println("Catched ALL")
}
finally {
println("finally running")
}
// case-in/case-is
let testStr = "123"
case testStr in { // in(徹底或部分匹配), is(徹底匹配)
"abc", "mno" { println("testStr is 'abc' or 'mno'") }
"def" { println("testStr is 'def'") }
`\d+` { println("testStr contains digit") }
else { println("testStr not matched") }
}
let i = [{"a"=>1, "b"=>2}, 10]
let x = [{"a"=>1, "b"=>2},10]
case i in {
1, 2 { println("i matched 1, 2") }
3 { println("i matched 3") }
x { println("i matched x") }
else { println("i not matched anything")}
}
複製代碼
在Monkey中,整型也是一個對象。所以,你能夠調用這個對象的方法。請看下面的例子:
x = (-1).next()
println(x) //0
x = -1.next() //equals 'x = -(1.next())
println(x) //-2
x = (-1).prev()
println(x) //-2
x = -1.prev() //equals 'x = -(1.prev())
println(x) //0
x = [i for i in 10.upto(15)]
println(x) //[10, 11, 12, 13, 14, 15]
for i in 10.downto(5) {
print(i, "") //10 9 8 7 6 5
}
println()
if 10.isEven() {
println("10 is even")
}
if 9.isOdd() {
println("9 is odd")
}
複製代碼
在Monkey中,浮點型也是一個對象。所以,你能夠調用這個對象的方法。請看下面的例子:
f0 = 15.20
println(f0)
f1 = 15.20.ceil()
println(f1)
f2 = 15.20.floor()
println(f2)
複製代碼
在Monkey中, 你可使用[]來初始化一個空的數組:
emptyArr = []
emptyArr[3] = 3 //將會自動擴容
println(emptyArr)
複製代碼
數組能夠包含任意數據類型的元素。
mixedArr = [1, 2.5, "Hello", ["Another", "Array"], {"Name"=>"HHF", "SEX"=>"Male"}]
複製代碼
你可使用索引來訪問數組元素。
println('mixedArr[2]={mixedArr[2]}')
println(["a", "b", "c", "d"][2])
複製代碼
由於數組是一個對象, 所以你可使用對象方法來操做它。
if ([].empty()) {
println("array is empty")
}
emptyArr.push("Hello")
println(emptyArr)
//你可使用'加算(+=)'的方式來向數組中添加一個元素:
emptyArr += 2
println(emptyArr)
複製代碼
可使用for
循環來遍歷一個數組。
numArr = [1,3,5,2,4,6,7,8,9]
for item in numArr where item % 2 == 0 {
println(item)
}
let strArr = ["1","a5","5", "5b","4","cc", "7", "dd", "9"]
for item in strArr where /^\d+/.match(item) {
println(item)
}
for item in ["a", "b", "c", "d"] where $_ % 2 == 0 { //$_是索引
printf("idx=%d, v=%s\n", $_, item)
}
複製代碼
你可使用內置函數reverse
來反轉數組元素:
let arr = [1,3,5,2,4,6,7,8,9]
println("Source Array =", arr)
revArr = reverse(arr)
println("Reverse Array =", revArr)
複製代碼
在monkey中, 有三種類型的string
:
\n
)\n
)原生字符串是一系列字符序列。使用反引號(``)來表示. 在原生字符串中,除了不能使用反引號外,你可使用其它的任意字符。
請看下面的例子:
normalStr = "Hello " + "world!"
println(normalStr)
println("123456"[2])
rawStr = `Welcome to
visit us!`
println(rawStr)
//當你但願一個變量在字符串中也可以被解析時,你可使用單引號。
//須要被解析的字符串放在花括號('{}')中:
str = "Hello world"
println('str={str}') //輸出: "Hello world"
str[6]="W"
println('str={str}') //輸出: "Hello World"
複製代碼
在monkey中, 字符串是utf8編碼的, 這說明你可使用utf8編碼的字符做爲變量名:
三 = 3
五 = 5
println(三 + 五) //輸出 : 8
複製代碼
字符串也是對象,你可使用strings
模塊中的方法來操做字符串:
upperStr = "hello world".upper()
println(upperStr) //輸出 : HELLO WORLD
複製代碼
字符串也能夠被遍歷:
for idx, v in "abcd" {
printf("idx=%d, v=%s\n", idx, v)
}
for v in "Hello World" {
printf("idx=%d, v=%s\n", $_, v) //$_是索引
}
複製代碼
你能夠鏈接一個對象到字符串:
joinedStr = "Hello " + "World"
joinedStr += "!"
println(joinedStr)
複製代碼
你還可使用內置函數reverse
來反轉字符串:
let str = "Hello world!"
println("Source Str =", str)
revStr = reverse(str)
println("Reverse str =", revStr)
複製代碼
在monkey中, 使用{}來建立一個空的哈希:
emptyHash = {}
emptyHash["key1"] = "value1"
println(emptyHash)
複製代碼
哈希的鍵(key)能夠是字符串(string),整型(int)或布爾型(boolean):
hashObj = {
12 => "twelve",
true => 1,
"Name" => "HHF"
}
println(hashObj)
複製代碼
你還可使用'+'或'-'來從一個哈希中增長或者刪除一個元素:
hashObj += {"key1" => "value1"}
hashObj += {"key2" => "value2"}
hashObj += {5 => "five"}
hashObj -= "key2"
hashObj -= 5
println(hash)
複製代碼
哈希也是一個對象,你可使用hash
模塊中的方法來操做哈希:
hashObj.push(15, "fifteen") //第一個參數是鍵,第二個參數是值
hashObj.pop(15)
keys = hashObj.keys()
println(keys)
values = hashObj.values()
println(values)
複製代碼
你還可使用內置函數reverse
來反轉哈希的key和value:
let hs = {"key1"=>12, "key2"=>"HHF", "key3"=>false}
println("Source Hash =", hs)
revHash = reverse(hs)
println("Reverse Hash =", revHash)
複製代碼
在Monkey中, tuple
與數組很是相似, 但一旦你建立了一個元祖,你就不可以更改它。
Tuples使用括號來建立:
//建立一個空元祖
let t1 = tuple()
//效果同上。注意:咱們必須放一個",", 不然編譯器將報錯
let t2 = (,)
// 建立僅有一個元素的元祖.
// 注意: 結尾的","是必須的,不然將會被解析爲(1), 而不是元祖
let t3 = (1,)
//建立有兩個元素的元祖
let t4 = (2,3)
複製代碼
你可使用內置函數tuple
,將任何類型的對象裝換爲元祖。
let t = tuple("hello")
println(t) // 結果: ("hello")
複製代碼
相似於數組, 元祖也能夠被索引(indexed),或切片(sliced)。 索引表達式tuple[i]
返回第i個索引位置的元祖元素, 切片表達式 tuple[i:j]返回一個子元祖.
let t = (1,2,3)[2]
print(t) // result:3
複製代碼
元祖還能夠被遍歷(相似數組),因此元祖可使用在for循環中,用在 列表推導中。
//for循環
for i in (1,2,3) {
println(i)
}
//元祖推導(comprehension)
let t1 = [x+1 for x in (2,4,6)]
println(t1) //result: [3, 5, 7]. 注意: 結果是數組,不是元祖
複製代碼
與數組不一樣,元祖不可以被修改。可是元祖內部的可變元素是能夠被修改的.
arr1 = [1,2,3]
t = (0, arr1, 5, 6)
println(t) // 結果: (0, [1, 2, 3], 5, 6)
arr1.push(4)
println(t) //結果: (0, [1, 2, 3, 4], 5, 6)
複製代碼
元祖也能夠用做哈希的鍵。
key1=(1,2,3)
key2=(2,3,4)
let ht = {key1 => 10, key2 =>20}
println(ht[key1]) // result: 10
println(ht[key2]) // result: 20
複製代碼
元祖可使用+
來鏈接,它會建立一個新的元祖。
let t = (1, 2) + (3, 4)
println(t) // 結果: (1, 2, 3, 4)
複製代碼
若是將元祖用在布爾環境中,那麼若是元祖的元素數量大於0, 那麼返回結果是true。
let t = (1,)
if t {
println("t is not empty!")
} else {
println("t is empty!")
}
//結果 : "t is not empty!"
複製代碼
在當前的tuple
實現中,對tuple
的操做還有一些不完善的地方,下面一併列舉:
t1 = () //錯誤。
t2 =(,) //正確。建立一個空的tuple
if (1,).empty() { //錯誤
println("tuple is empty!")
} else {
println("tuple is not empty!")
}
t = (1,)
if t.empty() { //正確
println("tuple is empty!")
} else {
println("tuple is not empty!")
}
let ht = {(1,2,3) => 10, (2,3,4) =>20} //錯誤!
println(ht[(1,2,3)]) //錯誤!
println(ht[(2,3,4)]) //錯誤!
key1=(1,2,3)
key2=(2,3,4)
let ht = {key1 => 10, key2 =>20} //正確
println(ht[key1]) // result: 10 //正確
println(ht[key2]) // result: 20 //正確
複製代碼
元祖的json序列化(反序列化)的結果都爲數組,而不是元祖
let tupleJson = ("key1","key2")
let tupleStr = json.marshal(tupleJson)
//結果: [
// "key1",
// "key2",
// ]
println(json.indent(tupleStr, " "))
let tupleJson1 = json.unmarshal(tupleStr)
println(tupleJson1) //結果: ["key1", "key2"]
複製代碼
元祖與一個數組相加,返回結果爲一個數組,而不是元祖.
t2 = (1,2,3) + [4,5,6]
println(t2) // 結果: [(1, 2, 3), 4, 5, 6]
複製代碼
你也可使用內置函數reverse
來反轉元祖中的元素:
let tp = (1,3,5,2,4,6,7,8,9)
println(tp) //結果: (1, 3, 5, 2, 4, 6, 7, 8, 9)
revTuple = reverse(tp)
println(revTuple) //結果: (9, 8, 7, 6, 4, 2, 5, 3, 1)
複製代碼
Monkey中預約義了下面三個對象: stdin
, stdout
, stderr
。分別表明標準輸入,標準輸出,標準錯誤
stdout.writeLine("Hello world")
//和上面效果同樣
fmt.fprintf(stdout, "Hello world\n")
print("Please type your name:")
name = stdin.read(1024) //從標準輸入讀最多1024字節
println("Your name is " + name)
複製代碼
當標準庫中的函數返回nil
或者false
的時候,你可使用它們的message()
方法類獲取錯誤信息:
file = newFile(filename, "r")
if (file == nil) {
println("opening ", filename, "for reading failed, error:", file.message())
}
//操做文件
//...
//關閉文件
file.close()
let ret = http.listenAndServe("127.0.0.1:9090")
if (ret == false) {
println("listenAndServe failed, error:", ret.message())
}
複製代碼
也許你會以爲奇怪,爲何nil
或false
有message()
方法? 由於在monkey中, nil
和false
兩個都是對象,所以它們都有方法。
defer
關鍵字defer
語句推遲(defer)某個函數的執行直到函數返回。
let add = fn(x,y){
defer println("I'm defer1")
println("I'm in add")
defer println("I'm defer2")
return x + y
}
println(add(2,2))
複製代碼
結果以下:
I'm in add I'm defer2
I'm defer1 4 複製代碼
Monkey中,你能夠聯接不一樣的類型。請看下面的例子:
// Number plus assignment
num = 10
num += 10 + 15.6
num += 20
println(num)
// String plus assignment
str = "Hello "
str += "world! "
str += [1, 2, 3]
println(str)
// Array plus assignment
arr = []
arr += 1
arr += 10.5
arr += [1, 2, 3]
arr += {"key"=>"value"}
println(arr)
// Array compare
arr1 = [1, 10.5, [1, 2, 3], {"key" => "value"}]
println(arr1)
if arr == arr1 { //support ARRAY compare
println("arr1 = arr")
} else {
println("arr1 != arr")
}
// Hash assignment("+=", "-=")
hash = {}
hash += {"key1" => "value1"}
hash += {"key2" => "value2"}
hash += {5 => "five"}
println(hash)
hash -= "key2"
hash -= 5
println(hash)
複製代碼
Monkey支持列表推導(列表能夠爲數組,字符串,Range,Tuple, 哈希)。 列表推導的返回值均爲數組。請看下面的例子:
//數組
x = [[word.upper(), word.lower(), word.title()] for word in ["hello", "world", "good", "morning"]]
println(x) //結果:[["HELLO", "hello", "Hello"], ["WORLD", "world", "World"], ["GOOD", "good", "Good"], ["MORNING", "morning", "Morning"]]
//字符串
y = [ c.upper() for c in "huanghaifeng" where $_ % 2 != 0] //$_ is the index
println(y) //結果:["U", "N", "H", "I", "E", "G"]
//範圍
w = [i + 1 for i in 1..10]
println(w) //結果:[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
//tuple
v = [x+1 for x in (12,34,56)]
println(v) //結果:[13, 35, 57]
//哈希
z = [v * 10 for k,v in {"key1"=>10, "key2"=>20, "key3"=>30}]
println(z) //結果:[100, 200, 300]
複製代碼
Monkey同時也支持哈希推導。 哈希推導的返回值均爲哈希。請看下面的例子:
//哈希推導 (from hash)
z1 = { v:k for k,v in {"key1"=>10, "key2"=>20, "key3"=>30}} //reverse key-value pair
println(z1) // 結果: {10 => "key1", 20 => "key2", 30 => "key3"}, 順序可能不一樣
//哈希推導 (from array)
z2 = {x:x**2 for x in [1,2,3]}
println(z2) // 結果: {1 => 1, 2 => 4, 3 => 9}, 順序可能不一樣
//哈希推導 (from .. range)
z3 = {x:x**2 for x in 5..7}
println(z3) // 結果: {5 => 25, 6 => 36, 7 => 49}, 順序可能不一樣
//哈希推導 (from string)
z4 = {x:x.upper() for x in "hi"}
println(z4) // 結果: {"h" => "H", "i" => "I"}, 順序可能不一樣
//哈希推導 (from tuple)
z5 = {x+1:x+2 for x in (1,2,3)}
println(z5) // 結果: {4 => 5, 2 => 3, 3 => 4}, 順序可能不一樣
複製代碼
grep
和map
相似於perl的grep
和map
.
let sourceArr = [2,4,6,8,10,12]
//$_表示每次循環取得的值
let m = grep $_ > 5, sourceArr //對每個sourceArr中的元素,僅返回">5"的元素
println('m is {m}')
let cp = map $_ * 2 , sourceArr //將每一個元素乘以2
println('cp is {cp}')
//一個複雜一點的例子
let fields = {
"animal" => "dog",
"building" => "house",
"colour" => "red",
"fruit" => "apple"
}
let pattern = `animal|fruit`
// =~(匹配), !~(不匹配)
let values = map { fields[$_] } grep { $_ =~ pattern } fields.keys()
println(values)
複製代碼
在Monkey中,函數和別的基礎類型同樣,可以做爲函數的參數,做爲函數的返回值
函數還能夠有缺省參數和可變參數。
//define a function
let add = fn() { [5,6] }
let n = [1, 2] + [3, 4] + add()
println(n)
let complex = {
"add" => fn(x, y) { return fn(z) {x + y + z } }, //function with closure
"sub" => fn(x, y) { x - y },
"other" => [1,2,3,4]
}
println(complex["add"](1, 2)(3))
println(complex["sub"](10, 2))
println(complex["other"][2])
let warr = [1+1, 3, fn(x) { x + 1}(2),"abc","def"]
println(warr)
println("\nfor i in 5..1 where i > 2 :")
for i in fn(x){ x+1 }(4)..fn(x){ x+1 }(0) where i > 2 {
if (i == 3) { continue }
println('i={i}')
}
// 缺省參數和可變參數
add = fn (x, y=5, z=7, args...) {
w = x + y + z
for i in args {
w += i
}
return w
}
w = add(2,3,4,5,6,7)
println(w)
複製代碼
你也能夠像下面這樣建立一個命名函數:
fn sub(x,y=2) {
return x - y
}
println(sub(10)) //結果 : 8
複製代碼
你還可使用短箭頭(short arraw)
語法來建立一個匿名函數:
let x = () -> 5 + 5
println(x()) //結果: 10
let y = (x) -> x * 5
println(y(2)) //結果: 10
let z = (x,y) -> x * y + 5
println(z(3,4)) //結果 :17
let add = fn (x, factor) {
x + factor(x)
}
result = add(5, (x) -> x * 2)
println(result) //結果 : 15
複製代碼
Monkey不支持多個返回值, 但有不少方法能夠達到目的.
下面是其中的一種實現方式:
fn div(x, y) {
if y == 0 {
return [nil, "y could not be zero"]
}
return [x/y, ""]
}
ret = div(10,5)
if ret[1] != "" {
println(ret[1])
} else {
println(ret[0])
}
複製代碼
pipe
操做符來自Elixir.
# Test pipe operator(|>)
x = ["hello", "world"] |> strings.join(" ") |> strings.upper() |> strings.lower() |> strings.title()
printf("x=<%s>\n", x)
let add = fn(x,y) { return x + y }
let pow = fn(x) { return x ** 2}
let subtract = fn(x) { return x - 1}
let mm = add(1,2) |> pow() |> subtract()
printf("mm=%d\n", mm)
"Hello %s!\n" |> fmt.printf("world")
複製代碼
你可使用spawn
來建立一個新的線程, chan
來和這個線程進行交互.
let aChan = chan()
spawn fn() {
let message = aChan.recv()
println('channel received message=<{message}>')
}()
//發送信息到線程
aChan.send("Hello Channel!")
複製代碼
Monkey中,預約義了一些標準模塊,例如:json, sql, sort, fmt, os, logger, time, flag, net, http等等。
下面是對monkey的標準模塊的一個簡短的描述。
let i, f, b, s, aArr, aHash = 108, 25.383, true, "Hello, world",
[1, 2, 3, 4, "a", "b"],
{ "key1" => 1, "key2" => 2, "key3" => "abc"}
//使用 '%v (value)' 來打印變量值, '%_' 來打印變量類型
fmt.printf("i=[%05d, %X], b=[%t], f=[%.5f], s=[%-15s], aArr=%v, aHash=%v\n", i, i, b, f, s, aArr, aHash)
fmt.printf("i=[%_], b=[%t], f=[%f], aArr=%_, aHash=%_, s=[%s] \n", i, b, f, aArr, aHash, s)
sp = fmt.sprintf("i=[%05d, %X], b=[%t], f=[%.5f], s=[%-15s]\n", i, i, b, f, s)
fmt.printf("sp=%s", sp)
fmt.fprintf(stdout, "Hello %s\n", "world")
複製代碼
t1 = newTime()
format = t1.strftime("%F %R")
println(t1.toStr(format))
Epoch = t1.toEpoch()
println(Epoch)
t2 = t1.fromEpoch(Epoch)
println(t2.toStr(format))
複製代碼
#輸出到標準輸出(stdout)
log = newLogger(stdout, "LOGGER-", logger.LSTDFLAGS | logger.LMICROSECONDS)
log.printf("Hello, %s\n", "logger")
fmt.printf("Logger: flags =<%d>, prefix=<%s>\n", log.flags(), log.prefix())
#輸出到文件
file = newFile("./logger.log", "a+")
log.setOutput(file)
for i in 1..5 {
log.printf("This is <%d>\n", i)
}
file.close() //別忘記關閉文件
複製代碼
let verV = flag.bool("version", false, "0.1")
let ageV = flag.int("age", 40, "an int")
let heightV = flag.float("height", 120.5, "a float")
let nameV = flag.string("name", "HuangHaiFeng", "a string")
let hobbiesV = flag.string("hobbies", "1,2,3", "a comma-delimited string")
flag.parse()
println("verV = ", verV)
println("ageV = ", ageV)
println("heightV = ", heightV)
println("nameV = ", nameV)
println("hobbies = ", hobbiesV.split(","))
if (flag.isSet("age")) {
println("age is set")
} else {
println("age is not set")
}
複製代碼
let hsJson = {"key1" => 10,
"key2" => "Hello Json %s %s Module",
"key3" => 15.8912,
"key4" => [1,2,3.5, "Hello"],
"key5" => true,
"key6" => {"subkey1"=>12, "subkey2"=>"Json"},
"key7" => fn(x,y){x+y}(1,2)
}
let hashStr = json.marshal(hsJson) //也可使用 `json.toJson(hsJson)`
println(json.indent(hashStr, " "))
let hsJson1 = json.unmarshal(hashStr)
println(hsJson1)
let arrJson = [1,2.3,"HHF",[],{ "key" =>10, "key1" =>11}]
let arrStr = json.marshal(arrJson)
println(json.indent(arrStr))
let arr1Json = json.unmarshal(arrStr) //也可使用 `json.fromJson(arrStr)`
println(arr1Json)
複製代碼
//簡單的TCP客戶端
let conn = dialTCP("tcp", "127.0.0.1:9090")
if (conn == nil) {
println("dailTCP failed, error:", conn.message())
os.exit(1)
}
let n = conn.write("Hello server, I'm client")
if (n == nil) {
println("conn write failed, error:", n.message())
os.exit(1)
}
let ret = conn.close()
if (ret == false) {
println("Server close failed, error:", ret.message())
}
//一個簡單的TCP服務端
let ln = listenTCP("tcp", ":9090")
for {
let conn = ln.acceptTCP()
if (conn == nil) {
println(conn.message())
} else {
printf("Accepted client, Address=%s\n", conn.addr())
}
spawn fn(conn) { //spawn a thread to handle the connection
println(conn.read())
}(conn)
} //end for
let ret = ln.close()
if (ret == false) {
println("Server close failed, error:", ret.message())
}
複製代碼
在Monkey中, linq
模塊支持下面的其中類型的對象:
newFile
建立)newCsvReader
建立)chan
建立)let mm = [1,2,3,4,5,6,7,8,9,10]
println('before mm={mm}')
result = linq.from(mm).where(fn(x) {
x % 2 == 0
}).select(fn(x) {
x = x + 2
}).toSlice()
println('after result={result}')
result = linq.from(mm).where(fn(x) {
x % 2 == 0
}).select(fn(x) {
x = x + 2
}).last()
println('after result={result}')
let sortArr = [1,2,3,4,5,6,7,8,9,10]
result = linq.from(sortArr).sort(fn(x,y){
return x > y
})
println('[1,2,3,4,5,6,7,8,9,10] sort(x>y)={result}')
result = linq.from(sortArr).sort(fn(x,y){
return x < y
})
println('[1,2,3,4,5,6,7,8,9,10] sort(x<y)={result}')
thenByDescendingArr = [
{"Owner" => "Google", "Name" => "Chrome"},
{"Owner" => "Microsoft", "Name" => "Windows"},
{"Owner" => "Google", "Name" => "GMail"},
{"Owner" => "Microsoft", "Name" => "VisualStudio"},
{"Owner" => "Google", "Name" => "GMail"},
{"Owner" => "Microsoft", "Name" => "XBox"},
{"Owner" => "Google", "Name" => "GMail"},
{"Owner" => "Google", "Name" => "AppEngine"},
{"Owner" => "Intel", "Name" => "ParallelStudio"},
{"Owner" => "Intel", "Name" => "VTune"},
{"Owner" => "Microsoft", "Name" => "Office"},
{"Owner" => "Intel", "Name" => "Edison"},
{"Owner" => "Google", "Name" => "GMail"},
{"Owner" => "Microsoft", "Name" => "PowerShell"},
{"Owner" => "Google", "Name" => "GMail"},
{"Owner" => "Google", "Name" => "GDrive"}
]
result = linq.from(thenByDescendingArr).orderBy(fn(x) {
return x["Owner"]
}).thenByDescending(fn(x){
return x["Name"]
}).toOrderedSlice() //Note: You need to use toOrderedSlice
//use json.indent() for formatting the output
let thenByDescendingArrStr = json.marshal(result)
println(json.indent(thenByDescendingArrStr, " "))
//測試 'selectManyByIndexed'
println()
let selectManyByIndexedArr1 = [[1, 2, 3], [4, 5, 6, 7]]
result = linq.from(selectManyByIndexedArr1).selectManyByIndexed(
fn(idx, x){
if idx == 0 { return linq.from([10, 20, 30]) }
return linq.from(x)
}, fn(x,y){
return x + 1
})
println('[[1, 2, 3], [4, 5, 6, 7]] selectManyByIndexed() = {result}')
let selectManyByIndexedArr2 = ["st", "ng"]
result = linq.from(selectManyByIndexedArr2).selectManyByIndexed(
fn(idx,x){
if idx == 0 { return linq.from(x + "r") }
return linq.from("i" + x)
},fn(x,y){
return x + "_"
})
println('["st", "ng"] selectManyByIndexed() = {result}')
複製代碼
如今,monkey有了一個支持linq for file
的功能。這個功能相似awk。 請看下面的代碼:
//test: linq for "file"
file = newFile("./examples/linqSample.csv", "r") //以讀取方式打開linqSample.csv
result = linq.from(file,",",fn(line){ //第二個參數爲字段分隔符, 第三個參數爲註釋函數(comment function)
if line.trim().hasPrefix("#") { //若是行以'#'開頭
return true //返回'true'表示忽略這一行
} else {
return false
}
}).where(fn(fields) {
//'fields'是一個哈希數組:
// fields = [
// {"line" =>LineNo1, "nf" =>line1's number of fields, 0 => line1, 1 => field1, 2 =>field2, ...},
// {"line" =>LineNo2, "nf" =>line2's number of fields, 0 => line2, 1 => field1, 2 =>field2, ...}
// ]
int(fields[1]) > 300000 //僅選取第一個字段的值 > 300000
}).sort(fn(field1,field2){
return int(field1[1]) > int(field2[1]) //第一個字段按照降序排列
}).select(fn(fields) {
fields[5] //僅輸出第五個字段
})
println(result)
file.close() //別忘記關閉文件
//another test: linq for "file"
file = newFile("./examples/linqSample.csv", "r") //以讀取方式打開linqSample.csv
result = linq.from(file,",",fn(line){ //第二個參數爲字段分隔符, 第三個參數爲註釋函數(comment function)
if line.trim().hasPrefix("#") { //若是行以'#'開頭
return true //返回'true'表示忽略這一行
} else {
return false
}
}).where(fn(fields) {
int(fields[1]) > 300000 //僅選取第一個字段的值 > 300000
}).sort(fn(field1,field2){
return int(field1[1]) > int(field2[1]) //第一個字段按照降序排列
}).selectMany(fn(fields) {
row = [[fields[0]]] //fields[0]爲整行數據。 注意:咱們須要使用兩個[], 不然selectMany()將會flatten輸出結果
linq.from(row) //輸出整行數據
})
println(result)
file.close() //別忘記關閉文件
//test: linq for "csv"
r = newCsvReader("./examples/test.csv") //以讀取方式打開test.csv
r.setOptions({"Comma"=>";", "Comment"=>"#"})
result = linq.from(r).where(fn(x) {
//The 'x' is an array of hashes, like below:
// x = [
// {"nf" =>line1's number of fields, 1 => field1, 2 =>field2, ...},
// {"nf" =>line2's number of fields, 1 => field1, 2 =>field2, ...}
// ]
x[2] == "Pike"//僅選取第二個字段 = "Pike"
}).sort(fn(x,y){
return len(x[1]) > len(y[1]) //以第一個字段的長度排序
})
println(result)
r.close() //別忘記關閉Reader
複製代碼
//測試 csv reader
let r = newCsvReader("./examples/test.csv")
if r == nil {
printf("newCsv returns err, message:%s\n", r.message())
}
r.setOptions({"Comma"=>";", "Comment"=>"#"})
ra = r.readAll()
if (ra == nil) {
printf("readAll returns err, message:%s\n", ra.message())
}
for line in ra {
println(line)
for record in line {
println(" ", record)
}
}
r.close() //do not to forget to close the reader
//測試 csv writer
let ofile = newFile("./examples/demo.csv", "a+")
let w = newCsvWriter(ofile)
w.setOptions({"Comma"=>" "})
w.write(["1", "2", "3"])
w.writeAll([["4", "5", "6"],["7", "8", "9"],["10", "11", "12"]])
w.flush()
ofile.close() //do not to forget to close the file
複製代碼
template
模塊包含'text'和'html'模版處理.
使用 newText(...)
或者 parseTextFiles(...)
來建立一個新的'text'模版。
使用 newHtml(...)
或者parseHtmlFiles(...)
來建立一個新的'html'模版。
arr = [
{ "key" => "key1", "value" => "value1" },
{ "key" => "key2", "value" => "value2" },
{ "key" => "key3", "value" => "value3" }
]
//使用parseTextFiles(), 來寫入一個字符串
template.parseTextFiles("./examples/looping.tmpl").execute(resultValue, arr)
println('{resultValue}')
//使用parseTextFiles()來寫入一個文件
file = newFile("./examples/outTemplate.log", "a+")
template.parseTextFiles("./examples/looping.tmpl").execute(file, arr)
file.close() //do not to forget to close the file
//使用 parse()
//注: 咱們須要使用"{{-" and "-}}"來移除輸出中的回車換行(newline)
template.newText("array").parse(`Looping
{{- range . }}
key={{ .key }}, value={{ .value -}}
{{- end }}
`).execute(resultValue, arr)
println('{resultValue}')
複製代碼
sql
模塊提供了一個底層封裝來操做數據庫。
它能夠正確的處理數據庫中的null值,雖然沒有通過徹底的測試。
爲了測試sql
模塊, 你須要作如下幾個步驟:
下載sql驅動器(sql driver)代碼.
將驅動器的包包含到'sql.go'文件中:
_ "github.com/mattn/go-sqlite3"
複製代碼
下面是一個完整的使用數據庫的例子(examples/db.my
):
let dbOp = fn() {
os.remove("./foo.db") //delete `foo.db` file
let db = dbOpen("sqlite3", "./foo.db")
if (db == nil) {
println("DB open failed, error:", db.message())
return false
}
defer db.close()
let sqlStmt = `create table foo (id integer not null primary key, name text);delete from foo;`
let exec_ret = db.exec(sqlStmt)
if (exec_ret == nil) {
println("DB exec failed! error:", exec_ret.message())
return false
}
let tx = db.begin()
if (tx == nil) {
println("db.Begin failed!, error:", tx.message())
return false
}
let stmt = tx.prepare(`insert into foo(id, name) values(?, ?)`)
if (stmt == nil) {
println("tx.Prepare failed!, error:", stmt.message())
return false
}
defer stmt.close()
let i = 0
for (i = 0; i < 105; i++) {
let name = "您好" + i
if (i>100) {
//插入`null`值. 有五個預約義的null常量:INT_NULL,FLOAT_NULL,STRING_NULL,BOOL_NULL,TIME_NULL.
let rs = stmt.exec(i, sql.STRING_NULL)
} else {
let rs = stmt.exec(i, name)
}
if (rs == nil) {
println("statement exec failed, error:", rs.message())
return false
}
} //end for
tx.commit()
let id, name = 0, ""
let rows = db.query("select id, name from foo")
if (rows == nil) {
println("db queue failed, error:", rows.message())
return false
}
defer rows.close()
while (rows.next()) {
rows.scan(id, name)
if (name.valid()) { //檢查是否爲`null`
println(id, "|", name)
} else {
println(id, "|", "null")
}
}
return true
}
let ret = dbOp()
if (ret == nil) {
os.exit(1)
}
os.exit()
複製代碼
項目還包含了一些使用的工具:formatter
和highlighter
。
formatter工具可以格式化monkey語言。 highlighter工具可以語法高亮monkey語言(提供兩種輸出:命令行和html)。
你也能夠將它們合起來使用:
./fmt xx.my | ./highlight //輸出到屏幕(命令行高亮不僅是windows)
複製代碼
目前,monkey支持三種編輯器的語法高亮:
vim
emeditor
notepad++
Visual Studio Code
Sublime Text 3
下面是對項目的將來計劃的描述:
MIT
若是你喜歡此項目,請點擊下面的連接,多多star,fork。謝謝! monkey