Go語(yǔ)言寫(xiě)的解析器(支持json,linq熙侍,sql榄鉴,net,http等)

Monkey程序語(yǔ)言

主頁(yè)

monkey

概述

Monkey是一個(gè)用go語(yǔ)言寫(xiě)的解析器. 語(yǔ)法借鑒了C, Ruby, Python和Perl.

總覽

此項(xiàng)目是基于mayoms的項(xiàng)目 monkey蛉抓,修改了其中的一些bug庆尘,同時(shí)增加了許多語(yǔ)言特性:

  • 更改了string模塊(能夠正確處理utf8字符編碼)
  • 修改了file模塊(包含一些新方法).
  • 增加了math模塊
  • 增加了sql(db)模塊(能夠正確的處理null值)
  • 增加了time模塊
  • 增加了sort模塊
  • 增加了os模塊
  • 增加了log模塊
  • 增加了net模塊
  • 增加了http模塊
  • 增加了filepath模塊
  • 增加了flag模塊(用來(lái)處理命令行參數(shù))
  • 增加了json模塊(json序列化和反序列化)
  • 增加了fmt模塊
  • 增加了sync模塊
  • 增加了list模塊
  • 增加了linq模塊(代碼來(lái)自linq并進(jìn)行了相應(yīng)的更改)
  • 增加了csv模塊
  • 增加了template模塊
  • 正則表達(dá)式支持(部分類(lèi)似于perl)
  • 管道(channel)(基于go語(yǔ)言的channel)
  • 更多的操作符支持(&&, ||, &, |, ^, +=, -=, ?: 等等)
  • utf8支持(例如,你可以使用utf8字符作為變量名)
  • 更多的流程控制支持(例如: try/catch/finally, for-in, case-in, 類(lèi)似c語(yǔ)言的for循環(huán))
  • defer支持
  • spawn支持(goroutine)
  • enum支持和
  • pipe操作符支持
  • 支持可變參數(shù)和缺省參數(shù)的函數(shù)

這個(gè)項(xiàng)目的目的主要有以下幾點(diǎn):

  • 自學(xué)go語(yǔ)言
  • 了解解析器的工作原理

但是巷送,解析器的速度并不是這個(gè)項(xiàng)目考慮的因素

安裝

下載本項(xiàng)目减余,運(yùn)行./run.sh

基本用法

你可以如下方式使用REPL:

~ ? monkey
Monkey programming language REPL

>>

或者運(yùn)行一個(gè)monkey文件:

monkey path/to/file

語(yǔ)言之旅

注釋

Monkey僅支持單行注釋.

// an inline comment
# another inline comment

數(shù)據(jù)類(lèi)型

Monkey支持7種基本類(lèi)型: String, Int, Float, Bool, Array, HashNil

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
n = nil

常量(字面值)

Monkey中,主要有9種類(lèi)型的常量(字面量).

  • Integer
  • Float
  • String
  • 正則表達(dá)式
  • Array
  • Hash
  • Nil
  • Boolean
  • Function
// 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}

// Nil literal
n = nil

// Boolean literals
t = true
f = false

// Function literals
let f = add(x, y) { return a + b }
println(f(1,2))

變量

你可以使用let來(lái)聲明一個(gè)變量惩系,或直接使用賦值的方式來(lái)聲明并賦值一個(gè)變量:variable=value.

let a = 1, b = "hello world", c = [1,2,3]
d = 4
e = 5
姓="黃"

保留字

下面列出了monkey語(yǔ)言的保留字:

  • fn
  • let
  • true false nil
  • if elsif elseif else
  • return
  • include
  • and or
  • enum
  • struct # 暫時(shí)沒(méi)使用
  • do while for break continue where
  • grep map
  • case is in
  • try catch finally throw
  • defer
  • spawn
  • yield #not used
  • qw

類(lèi)型轉(zhuǎn)換

你可以使用內(nèi)置的方法:int(), float(), str(), array()來(lái)進(jìn)行不同類(lèi)型之間的轉(zhuǎn)換.

let i = 0xa
let s = str(i)     // result: "10"
let f = float(i)   // result: 10
let a = array(i)   // result: [10]

qw(Quote word)關(guān)鍵字

qw關(guān)鍵字類(lèi)似perl的qw關(guān)鍵字. 當(dāng)你想使用很多的雙引號(hào)字符串時(shí),qw就是一個(gè)好幫手.

for str in qw<abc, def, ghi, jkl, mno> { //允許的成對(duì)操作符:'{}', '<>', '()'
  println('str={str}')
}

newArr = qw(1,2,3.5) //注:這里的newArr是一個(gè)字符串?dāng)?shù)組位岔,不是一個(gè)整形數(shù)組.
fmt.printf("newArr=%v\n", newArr)

enum關(guān)鍵字

在mokey中,你可以使用enum來(lái)定義常量.

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`的所有名稱(chēng)
for s in LogOption.getNames() { //非排序(non-ordered)
    println(s)
}

//得到`enum`的所有值
for s in LogOption.getValues() { //非排序(non-ordered)
    println(s)
}

// 得到`enum`的一個(gè)特定的名字
println(LogOption.getName(LogOption.Lshortfile))

控制流程

  • If-else
  • for-in
  • while
  • do
  • try-catch-finally
  • case-in/case-is
// if-else
let a= 10, b = 5
if (a > b) { // '()'可選, 但是'{}'必須要有
    println("a > b")
}
elseif a == b { // 也可以使用'elsif'
    println("a = b")
}
else {
    println("a < b")
}

// for
i = 9
for { // 無(wú)限循環(huán)
    i = i + 2
    if (i > 20) { break }
    println('i = {i}')
}


i = 0
for (i = 0; i < 5; i++) {  // 類(lèi)似c語(yǔ)言的for循環(huán)堡牡, '()'必須要有
    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循環(huán)是個(gè)表達(dá)式(expression),而不是一個(gè)語(yǔ)句(statement), 因此它能夠被賦值給一個(gè)變量
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一個(gè)string類(lèi)型的變量)
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")}
}

標(biāo)準(zhǔn)輸入/輸出/錯(cuò)誤

Monkey中預(yù)定義了下面三個(gè)對(duì)象: stdin, stdout, stderr抒抬。分別代表標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出晤柄,標(biāo)準(zhǔn)錯(cuò)誤

fmt.fprintf(stdout, "Hello world\n")

print("Please type your name:")
name = stdin.read(1024)  //從標(biāo)準(zhǔn)輸入讀最多1024字節(jié)
println("Your name is " + name)

標(biāo)準(zhǔn)庫(kù)中的錯(cuò)誤處理

當(dāng)標(biāo)準(zhǔn)庫(kù)中的函數(shù)返回nil或者false的時(shí)候擦剑,你可以使用它們的message()方法類(lèi)獲取錯(cuò)誤信息:

file = newFile(filename, "r")
if (file == nil) {
    println("opening ", filename, "for reading failed, error:", file.message())
}


let ret = http.listenAndServe("127.0.0.1:9090")
if (ret == false) {
    println("listenAndServe failed, error:", ret.message())
}

也許你會(huì)覺(jué)得奇怪,為什么nilfalsemessage()方法芥颈? 因?yàn)樵趍onkey中, nilfalse兩個(gè)都是對(duì)象惠勒,因此它們都有方法。

關(guān)于defer關(guān)鍵字

defer語(yǔ)句推遲(defer)某個(gè)函數(shù)的執(zhí)行直到函數(shù)返回爬坑。

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))

結(jié)果如下:

I'm in add
I'm defer2
I'm defer1
4

不同類(lèi)型的聯(lián)接

Monkey中纠屋,你可以聯(lián)接不同的類(lèi)型。請(qǐng)看下面的例子:

// 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)

Grep和map

grepmap類(lèi)似于perl的grepmap.

let sourceArr = [2,4,6,8,10,12]

//$_表示每次循環(huán)取得的值
let m = grep  $_ > 5, sourceArr //對(duì)每一個(gè)sourceArr中的元素盾计,僅返回">5"的元素
println('m is {m}')

let cp = map $_ * 2 , sourceArr //將每個(gè)元素乘以2
println('cp is {cp}')

//一個(gè)復(fù)雜一點(diǎn)的例子
let fields = {
                "animal"   => "dog",
                "building" => "house",
                "colour"   => "red",
                "fruit"    => "apple"
             }
let pattern = `animal|fruit`
// =~(匹配), !~(不匹配)
let values = map { fields[$_] } grep { $_ =~ pattern } fields.keys()
println(values)

函數(shù)

在Monkey中售担,函數(shù)和別的基礎(chǔ)類(lèi)型一樣赁遗,能夠作為函數(shù)的參數(shù),作為函數(shù)的返回值

函數(shù)還可以有缺省參數(shù)和可變參數(shù)族铆。

//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}')
}


// 缺省參數(shù)和可變參數(shù)
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)

Pipe操作符

pipe操作符來(lái)自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)

Spawn 和 channel

你可以使用spawn來(lái)創(chuàng)建一個(gè)新的線(xiàn)程, chan來(lái)和這個(gè)線(xiàn)程進(jìn)行交互.

let aChan = chan()
spawn fn() {
    let message = aChan.recv()
    println('channel received message=<{message}>')
}()

//發(fā)送信息到線(xiàn)程
aChan.send("Hello Channel!")

標(biāo)準(zhǔn)模塊介紹

Monkey中,預(yù)定義了一些標(biāo)準(zhǔn)模塊岩四,例如:json, sql, sort, fmt, os, logger, time, flag, net, http等等。

下面是對(duì)monkey的標(biāo)準(zhǔn)模塊的一個(gè)簡(jiǎn)短的描述哥攘。

//fmt module
let i = 108, f = 25.383, b=true, s = "Hello, world",
    aArr = [1, 2, 3, 4, "a", "b"],
    aHash = { "key1" => 1, "key2" => 2, "key3" => "abc"}

// Use '%v (value)' to print variable value, '%_' to print the variable's type
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")


//time module
t1 = newTime()
format = t1.strftime("%F %R")
println(t1.toStr(format))
Epoch = t1.toEpoch()
println(Epoch)

t2 = t1.fromEpoch(Epoch)
println(t2.toStr(format))


//logger module
#Log to 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())

#Log to file
file = newFile("./logger.log", "a+")
log.setOutput(file)
for i in 1..5 {
    log.printf("This is <%d>\n", i)
}


//flag module(for handling of command line options)
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")
}


// json module( for json marshal & unmarshal)
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) //same as `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)  //same as `json.fromJson(arrStr)`
println(arr1Json)


//net module
//A simple tcp client
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())
}

//A simple tcp server
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())
}



//linq module
//the linq module is not fully tested, and it has no `orderby` and `compare` compared with
//ahmetb's linq implementation.
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, "  "))

//test '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}')



//csv module
//test 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)
    }
}

//test 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()


實(shí)用工具

項(xiàng)目還包含了一些使用的工具:formatterhighlighter剖煌。

formatter工具能夠格式化monkey語(yǔ)言。
highlighter工具能夠語(yǔ)法高亮monkey語(yǔ)言(提供兩種輸出:命令行和html)逝淹。

你也可以將它們合起來(lái)使用:

./fmt xx.my | ./highlight  //輸出到屏幕(命令行高亮不只是windows)

數(shù)據(jù)庫(kù)處理

在Monkey語(yǔ)言中末捣,標(biāo)準(zhǔn)模塊sql提供了對(duì)數(shù)據(jù)庫(kù)底層的支持。同時(shí)支持?jǐn)?shù)據(jù)庫(kù)中對(duì)于null的處理创橄。
請(qǐng)看下面的完整示例代碼:

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) {
            //這里是對(duì)null的支持(插入null值)箩做,有五個(gè)預(yù)定義的null常量(具體請(qǐng)參看sql.go文件)
            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 = 0, name = ""
    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)
        //查詢(xún)從DB中取出的值是否為null
        if (name.valid()) { //check if it's `null`
            println(id, "|", name)
        } else {
            println(id, "|", "null")
        }
    }
    return true
}

let ret = dbOp()
if (ret == nil) {
    os.exit(1)
}

os.exit()

未來(lái)計(jì)劃

下面是對(duì)項(xiàng)目的未來(lái)計(jì)劃的描述:

  • 改進(jìn)標(biāo)準(zhǔn)庫(kù)并增加更多的函數(shù).
  • 寫(xiě)更多的測(cè)試代碼!

許可證

MIT

備注

如果你喜歡此項(xiàng)目,請(qǐng)點(diǎn)擊下面的鏈接妥畏,多多star邦邦,fork。謝謝醉蚁!
monkey

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末燃辖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子网棍,更是在濱河造成了極大的恐慌黔龟,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滥玷,死亡現(xiàn)場(chǎng)離奇詭異氏身,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)惑畴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)蛋欣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人如贷,你說(shuō)我怎么就攤上這事陷虎。” “怎么了杠袱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵尚猿,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我楣富,道長(zhǎng)凿掂,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任菩彬,我火速辦了婚禮缠劝,結(jié)果婚禮上潮梯,老公的妹妹穿的比我還像新娘骗灶。我一直安慰自己惨恭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布耙旦。 她就那樣靜靜地躺著脱羡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪免都。 梳的紋絲不亂的頭發(fā)上锉罐,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音绕娘,去河邊找鬼脓规。 笑死,一個(gè)胖子當(dāng)著我的面吹牛险领,可吹牛的內(nèi)容都是我干的侨舆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绢陌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼憔购!你這毒婦竟也來(lái)了欠拾?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎檐盟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體犁享,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡再来,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闻鉴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片帜讲。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖椒拗,靈堂內(nèi)的尸體忽然破棺而出似将,到底是詐尸還是另有隱情,我是刑警寧澤蚀苛,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布在验,位于F島的核電站,受9級(jí)特大地震影響堵未,放射性物質(zhì)發(fā)生泄漏腋舌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一渗蟹、第九天 我趴在偏房一處隱蔽的房頂上張望块饺。 院中可真熱鬧赞辩,春花似錦、人聲如沸授艰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)淮腾。三九已至糟需,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谷朝,已是汗流浹背洲押。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留圆凰,地道東北人杈帐。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像专钉,于是被迫代替她去往敵國(guó)和親挑童。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,789評(píng)論 25 707
  • 最近發(fā)生的一些事情驶沼,讓自己莫名的有一些不淡定炮沐。好吧,我們就叫它傷感吧回怜! 作為一個(gè)任何自己周?chē)l(fā)生的事情大年,都要做一個(gè)...
    叫我大叔閱讀 343評(píng)論 1 2
  • 三國(guó)開(kāi)篇曰,天下大勢(shì)玉雾,分久必合翔试,合久必分。然楚河漢界之爭(zhēng)雄雖經(jīng)數(shù)千年仍戰(zhàn)事不息复旬。 好弈者約棋友于靜處垦缅,一石枰,兩竹...
    風(fēng)寒路遠(yuǎn)閱讀 565評(píng)論 1 2
  • request 打印所有的參數(shù): HTTP server is listening at port 3000. I...
    小蘇008閱讀 2,005評(píng)論 1 0