NOTE:
vast tool has been merged to v project. please use:
v ast demo.v generate demo.json file.
v ast -w demo.v generate demo.json file, and watch for changes.
v ast -c demo.v generate demo.json and demo.c file, and watch for changes.
v ast -p demo.v print the json string to stdout, instead of saving it to a file.
A simple tool for vlang, generate v source file to AST json file.
It will generate example code to AST json file, which can help you understand the AST better.
- via vpm
v install lydiandy.vast
- via source
git clone git@github.com:lydiandy/vast.git
ln -s `pwd`/vast ~/.vmodules/vast
build
cd vast
v -prod .
vast demo.v //generate demo.json.
vast -w demo.v //generate demo.json and watch.
vast -p demo.v //print the json string to termial.
./vast ./example/demo.v
it will parse the demo.v file and generate demo.json, open it ~
or you can parse the vlib/builtin/array.v
vast your/v/dir/vlib/builtin/array.v
it will generate array.json file, ~22000 lines json code.
The Vlang abstract syntax tree is implemented by using sum type.
All the AST struct declarations can be found in V source code: vlib/v/ast/ast.v.
AST struct
File
example code
module main
import os
import time
fn main() {
}
AST struct
Module
Import
example code
module main
import os
import time as t
import math { min, max }
AST struct
Const
example code
module main
const single_const = 'abc'
const (
// version comment 1
version = '0.2.0' // version comment 2
usage = 'usage:xxxx'
pi = 3.14
//end comment 1
//end comment 2
)
AST struct
EnumDecl
EnumField
EnumVal
example code
module main
[attr1]
['attr2:123']
enum Color { // enum comment 1
// black comment 1
// black comment 2
black = 2 // black comment 3
// white comment 1
// white comment 2
white // white comment 3
blue
green // green comment
// end comment 1
// end comment 2
}
[flag]
enum BitEnum {
e1
e2
e3
}
[_allow_multiple_values]
enum MultipleEnum {
v1 = 1
}
fn main() {
mut color := Color.black
color = .blue
}
AST struct
AssignStmt
example code
module main
fn main() {
// an assignment
a := 'abc' // comment for a
mut b := 1
// more operator
b = 2
b += 2
b -= 2
b *= 2
b /= 2
b %= 2
// multi assign
x, y, z := 1, 'y', 3.3
mut xx, mut yy, zz := 1, 3, 5
// swap variable
mut c := 1
mut d := 2
c, d = d, c
}
AST struct
Ident
IdentFn
IdentVar
example code
module main
fn main() {
i := 123 // common(unresolved) identifier
_, x := 1, 2 // blank identifier
mut s := 'abc' // with mut
s = 'aaa'
}
AST struct
IntegerLiteral
FloatLiteral
StringLiteral
StringLiteral
StringInterLiteral
CharLiteral
BoolLiteral
example code
module main
fn main() {
a := 1 // integer literal
b := 1.2 // float literal
c := 'abc' // string literal
name:='tom'
age:= 33
//string literal with `$xx` or `${xxx}`
s1 := 'a is $a,b is $b,c is $c'
s2 := 'name is ${name}, age is ${age}'
e := `c` // char literal
f := true // bool literal
}
AST struct
AsCast
example code
module main
type Mysumtype = bool | f64 | int | string
fn main() {
x := Mysumtype(3)
x2 := x as int // as must be used for sumtype
println(x2)
}
AST struct
SizeOf
example code
module main
struct Point {
x int
y int
}
fn main() {
a := sizeof(int) // basic type
b := sizeof(bool) // basic type
p := Point{
x: 1
y: 2
}
s1 := sizeof(Point) // struct type
s2 := sizeof(p) // variable
}
AST struct
TypeOf
example code
module main
type MySumType = f32 | int
fn myfn(i int) int {
return i
}
fn main() {
a := 123
s := 'abc'
aint := []int{}
astring := []string{}
println(typeof(a)) // int
println(typeof(s)) // string
println(typeof(aint)) // array_int
println(typeof(astring)) // array_string
// sumtype
sa := MySumType(32)
println(typeof(sa)) // int
// function type
println(typeof(myfn)) // fn (int) int
}
AST struct
CastExpr
example code
module main
fn main() {
x:=byte(3)
y:=f32(2.1)
}
AST struct
ArrayInit
example code
module main
fn main() {
mut arr := []string{len: 3, cap: 6, init: 'default'}
arr[0] = 'a'
arr[1] = 'b'
println(arr)
}
AST struct
IndexExpr
example code
module main
fn main() {
mut arr := []string{len: 3, cap: 6, init: 'default'}
arr[0] = 'a' //index expr
arr[1] = 'b'
println(arr)
mut m := map[string]string{}
m['name'] = 'tom' //index expr
m['age'] = '33'
}
AST struct
RangeExpr
example code
module main
fn main() {
n := [1, 2, 3, 4, 5]
a1 := n[..2] //[1, 2]
a2 := n[2..] //[3, 4, 5]
a3 := n[2..4] //[3, 4]
}
AST struct
ArrayDecompose
example code
module main
fn main() {
a := ['a', 'b', 'c']
println(variadic_fn_a(...a)) //ArrayDecompose
}
fn variadic_fn_a(a ...string) string {
return variadic_fn_b(...a) //ArrayDecompose
}
fn variadic_fn_b(a ...string) string {
a0 := a[0]
a1 := a[1]
a2 := a[2]
return '$a0$a1$a2'
}
AST struct
MapInit
example code
module main
fn main() {
mut m := map[string]string{} //map declaration
m['name'] = 'tom'
m['age'] = '33'
//map literal declaration and init
m2 := {
'one': 1
'two': 2
'three': 3
}
}
AST struct
PrefixExpr
example code
module main
fn main() {
x := -1 // minus
p := &x // get address of variable
x2 := *p // get value of pointer
b := !true // logic not
bit := ~0x0000 // bit not
}
AST struct
InfixExpr
example code
module main
fn main() {
x := 1 + 2
y := 1 - 2
a := x == y // equal
b := x > y // compare
c := 1 in [1, 2] // in operator
d := (x > y) && (1 < 2) // logic and
e := 2 == 2 || 3 == 3 // logic or
mut arr := [1, 2] // array append
arr << 3
}
AST struct
PostfixExpr
example code
module main
fn main() {
mut x:=1
x++
x--
}
AST struct
SelectorExpr
example code
module main
struct Point {
mut:
x int
y int
}
fn (mut p Point) move(a int, b int) {
p.x += a // selector for struct field assign
p.y += b
}
fn main() {
mut p := Point{
x: 1
y: 3
}
p.x // selector for access field value
p.move(2, 3)
}
AST struct
ParExpr
example code
module main
fn main() {
x:=(1+2)
y:=(1<2)
}
AST struct
ConcatExpr
example code
a, b, c := match false {
true { 1, 2, 3 }
false { 4, 5, 6 }
else { 7, 8, 9 }
}
AST struct
FnDecl
CallExpr
CallArg
Return
example code
module main
fn main() {
s := add(1, 3)
println(s)
s2 := add_generic(2, 4)
s3 := add_generic<int>(2, 4)
println(s2)
println(s3)
}
// function
fn add(x int, y int) int {
return x + y
}
struct Point {
x int
y int
}
// method
pub fn (p Point) move(a int, b int) (int, int) {
new_x := p.x + a
new_y := p.y + b
return new_x, new_y
}
// generic function
fn add_generic<T>(x T, y T) T {
return x + y
}
AST struct
AnonFn
example code
module main
fn main() {
f1 := fn (x int, y int) int {
return x + y
}
f1(1,3)
}
AST struct
DeferStmt
example code
fn main() {
println('main start')
// defer {defer_fn1()}
// defer {defer_fn2()}
defer {
defer_fn1()
}
defer {
defer_fn2()
}
println('main end')
}
fn defer_fn1() {
println('from defer_fn1')
}
fn defer_fn2() {
println('from defer_fn2')
}
AST struct
StructDecl
StructField
Embed
example code
module main
[attr1]
[attr2]
struct Point { //comment 1
mut:
x int [attr3]
y int ['attr4=123']
pub mut:
z int = 1
//end comment
}
fn main() {
}
example code of embed
module main
struct Widget {
mut:
x int
y int
}
pub fn (mut w Widget) move(x_step int, y_step int) {
w.x += x_step
w.y += y_step
}
struct Widget2 {
mut:
z int
}
pub fn (mut w Widget2) move_z(z_step int) {
w.z += z_step
}
struct Button {
Widget //embed
Widget2 //embed
title string
}
fn main() {
mut button := Button{
title: 'Click me'
}
button.x = 3 // x comes from Widget
button.z = 4 // z comes from Widget2
println('x:$button.x,y:$button.y,z:$button.z')
button.move(3, 4) // move comes from Widget
println('x:$button.x,y:$button.y,z:$button.z')
button.move_z(5) // move_z comes from Widget2
println('x:$button.x,y:$button.y,z:$button.z')
}
AST struct
StructInit
StructInitField
StructInitEmbed
example code
module main
struct User {
name string
age int
}
fn add(u User) {
println(u)
}
fn main(){
add(User{name:'jack',age:22}) //standard
add({name:'tom',age:23}) //short
add(name:'tt',age:33) // more short
}
example code with update expr
struct City {
name string
population int
}
struct Country {
name string
capital City
}
fn main() {
ccc := Country{
name: 'test'
capital: City{
name: 'city'
}
}
c2 := Country{
...ccc //update_expr
capital: City{
name: 'city2'
population: 200
}
}
println(c2)
}
AST struct
Assoc(deprecated, use update_expr)
example code
struct Foo {
a int
b int
c int = 7
}
fn main() {
foo := Foo{
a: 1
b: 33
}
//associate
foo2 := {
foo |
a: 42
b: 10
}
println(foo2.a) // 42
println(foo2.b) // 10
println(foo2.c) // 7
}
AST struct
InterfaceDecl
example code
module main
interface Speaker { //comment 1
speak() string
silent()
}
AST struct
AliasTypeDecl
example code
module main
struct Human {
name string
}
type Myint = int /*comment 1*/ //comment 2
type Person = Human
AST struct
FnTypeDecl
example code
module main
type Mid_fn = fn (int, string) int /*comment 1*/ //comment 2
AST struct
SumTypeDecl
example code
module main
struct User {
name string
age int
}
type MySumtype = User | int | string //comment 1
AST struct
Block
example code
fn main() {
my_fn()
}
fn my_fn() {
// block
{
println('in block')
}
// unsafe block
unsafe {
}
}
AST struct
IfExpr
IfBranch
example code
module main
fn main() {
a := 10
b := 20
// if statement
if a < b {
println('$a < $b')
} else if a > b {
println('$a > $b')
} else {
println('$a == $b')
}
// if expr
num := 777
s := if num % 2 == 0 { 'even' } else { 'odd' }
x, y, z := if true { 1, 'awesome', 13 } else { 0, 'bad', 0 }
// compile time if
$if macos {
} $else {
}
}
AST struct
MatchExpr
MatchBranch
example code
fn main() {
os := 'macos'
// match statement
match os {
'windows' { println('windows') }
'macos', 'linux' { println('macos or linux') }
else { println('unknow') }
}
// match expr
price := match os {
'windows' { 100 }
'linux' { 120 }
'macos' { 150 }
else { 0 }
}
// multi assign
a, b, c := match false {
true { 1, 2, 3 }
false { 4, 5, 6 }
else { 7, 8, 9 }
}
}
type MySum = bool | int | string
pub fn (ms MySum) str() string {
// match sum type
match ms {
int { return ms.str() }
string { return ms }
else { return 'unknown' }
}
}
AST struct
ForCStmt
ForInStmt
ForStmt
BranchStmt
example code
fn main() {
for i := 0; i < 10; i++ {
if i == 6 {
continue
}
if i == 10 {
break
}
println(i)
}
}
example code
fn main() {
// string
str := 'abcdef'
for s in str {
println(s.str())
}
// array
numbers := [1, 2, 3, 4, 5]
for num in numbers {
println('num:$num')
}
// range
mut sum := 0
for i in 1 .. 11 {
sum += i
}
// map
m := {
'name': 'jack'
'age': '20'
'desc': 'good man'
}
for key, value in m {
println('key:$key,value:$value')
}
}
example code
fn main() {
mut sum := 0
mut x := 0
for x <= 100 {
sum += x
x++
}
println(sum)
// label for
mut i := 4
goto L1
L1: for { // label for
i++
for {
if i < 7 {
continue L1
} else {
break L1
}
}
}
}
AST struct
GotoLabel
GotoStmt
example code
fn main() {
mut i := 0
a: // goto label
i++
if i < 3 {
goto a
}
println(i)
}
AST struct
OrExpr
None
example code
fn my_fn(i int) ?int {
if i == 0 {
return error('Not ok!')
}
if i == 1 {
return none
}
return i
}
fn main() {
println('from main') // OrKind is absent
v1 := my_fn(0) or { // OrKind is block
println('from 0')
panic(err)
}
v2 := my_fn(1) or {
println('from 1')
panic('error msg is $err')
}
v3 := my_fn(2) or {
println('from 2')
return
}
v4 := my_fn(3) ? // OrKind is propagate
}
AST struct
ChanInit
GoStmt
example code
module main
const (
num_iterations = 10000
)
fn do_send(ch chan int) {
for i in 0 .. num_iterations {
ch <- i
}
}
fn main() {
ch := chan int{cap: 1000} // chan init
go do_send(ch) // go statement
mut sum := i64(0)
for _ in 0 .. num_iterations {
sum += <-ch
println(sum)
}
}
AST struct
SelectExpr
SelectBranch
example code
import time
import sync
fn main() {
ch1 := chan int{}
ch2 := chan int{}
go send(ch1, ch2)
mut x := 0
mut y := 0
for {
select { //
x = <-ch1 { // read channel
println('$x')
}
y = <-ch2 {
println('$y')
}
> 2 * time.second { // timeout
break
}
}
}
}
fn send(ch1 chan int, ch2 chan int) {
ch1 <- 1
ch2 <- 2
ch1 <- 3
ch2 <- 4
ch1 <- 5
ch2 <- 6
}
AST struct
LockExpr
example code
module main
import time
struct St {
mut:
x f64
}
fn f(x int, y f64, shared s St,shared m map[string]string) {
time.usleep(50000)
lock s,m {
s.x = x * y
println(s.x)
unsafe {
m['a']='aa'
}
println(m['a'])
}
return
}
fn main() {
shared t := &St{}
shared m := &map[string]string
unsafe {
m['a']='aa'
}
r := go f(3, 4.0, shared t,shared m)
r.wait()
rlock t {
println(t.x)
}
}
AST struct
GoExpr
example code
module main
import time
fn do_something() {
println('start do_something...')
time.sleep(2)
println('end do_something')
}
fn add(x int, y int) int {
println('add start...')
time.sleep(4) //
println('end add')
return x + y
}
fn main() {
g:= go do_something()
g2 := go add(3, 2)
g.wait()
result := g2.wait()
println(result)
}
AST struct
UnsafeExpr
example code
module main
fn main() {
a := ['a', 'b', 'c']
p := unsafe { &a[2] } // unsafe expr
println(p)
}
AST struct
AsmStmt
AsmTemplate
AsmClobbered
AsmIO
AsmArg
AsmAddressing
AsmAlias
AsmRegister
example code
fn main() {
a := 100
b := 20
mut c := 0
asm amd64 {
mov eax, a
add eax, b
mov c, eax
; =r (c) // output
; r (a) // input
r (b)
}
println('a: $a') // 100
println('b: $b') // 20
println('c: $c') // 120
}
AST struct
SqlStmt
SqlExpr
example code
module main
import sqlite
struct Module {
id int
name string
nr_downloads int
}
struct User {
id int
age int
name string
is_customer bool
skipped_string string [skip]
}
struct Foo {
age int
}
fn main() {
db := sqlite.connect(':memory:') or { panic(err) }
db.exec('drop table if exists User')
db.exec("create table User (id integer primary key, age int default 0, name text default '', is_customer int default 0);")
name := 'Peter'
db.exec("insert into User (name, age) values ('Sam', 29)")
db.exec("insert into User (name, age) values ('Peter', 31)")
db.exec("insert into User (name, age, is_customer) values ('Kate', 30, 1)")
nr_all_users := sql db {
select count from User
}
println('nr_all_users=$nr_all_users')
//
nr_users1 := sql db {
select count from User where id == 1
}
println('nr_users1=$nr_users1')
//
nr_peters := sql db {
select count from User where id == 2 && name == 'Peter'
}
//
new_user := User{
name: 'New user'
age: 30
}
sql db {
insert new_user into User
}
sql db {
update User set age = 31 where name == 'Kate'
}
sql db {
delete from User where age == 34
}
}
AST struct
AssertStmt
example code
fn test_abc() {
x := 1
assert x == 1
}
AST struct
CompFor
ComptimeCall
example code
struct App {
a string
b string
mut:
c int
d f32
pub:
e f32
f u64
pub mut:
g string
h byte
}
fn (mut app App) m1() {
}
fn (mut app App) m2() {
}
fn (mut app App) m3() int {
return 0
}
fn main() {
$for field in App.fields {
println('field: $field.name')
}
$for method in App.methods {
println('method: $method.name')
}
}
AST struct
GlobalDecl
GlobalField
example code
module main
// single
__global ( g1 int )
// group
__global (
g2 byteptr
g3 byteptr
)
fn main() {
g1 = 123
println(g1)
println(g2)
println(g3)
}
AST struct
HashStmt
example code
module main
#include <stdio.h>
#flag -lmysqlclient
#flag linux -I/usr/include/mysql
#include <mysql.h>
fn main() {
}
AST struct
Likely
example code
module main
fn main() {
x := 1
if _likely_(x == 1) {
println('a')
} else {
println('b')
}
if _unlikely_(x == 1) {
println('a')
} else {
println('b')
}
}
AST struct
OffsetOf
example code
module main
struct User {
name [50]byte
age int
desc string
}
fn main() {
offset_name:=__offsetof(User,name)
offset_age:=__offsetof(User,age)
offset_desc:=__offsetof(User,desc)
println(offset_name)
println(offset_age)
println(offset_desc)
}
AST struct
Comment
example code
module main
/*
multi line comment
multi line comment
*/
// signle line comment
fn main() {
x := 1 // behind statement comment
}
AST struct
AtExpr
example code
module main
fn main() {
println(@MOD)
println(@FN)
println(@STRUCT)
println(@VEXE)
println(@FILE)
println(@LINE)
println(@COLUMN)
println(@VHASH)
println(@VMOD_FILE)
}
MIT
pull request is welcome ~