Home

Awesome

vast

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.

Installation

v install lydiandy.vast
git clone git@github.com:lydiandy/vast.git
ln -s `pwd`/vast ~/.vmodules/vast

build

cd vast
v -prod .

Usage

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.

Vlang AST struct diagram

Vlang AST struct introduction

Overview

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.

File

AST struct

File

example code

module main

import os
import time

fn main() {
  
}

Module

AST struct

Module

Import

example code

module main

import os
import time as t
import math { min, max }

Const

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
)

Enum

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
}

Variable

Assign

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
}

Identifier

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

Literal

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
}

AsCast

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

SizeOf

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
}

TypeOf

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
}

CastExpr

AST struct

CastExpr

example code

module main

fn main() {
	x:=byte(3)
	y:=f32(2.1)
}

Array

ArrayInit

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

IndexExpr

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

RangeExpr

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]
}

ArrayDecompose

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

Map

MapInit

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

Operator

PrefixExpr

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
}

InfixExpr

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
}

PostfixExpr

AST struct

PostfixExpr

example code

module main

fn main() {
	mut x:=1
	x++
	x--
}

SelectorExpr

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

ParExpr

AST struct

ParExpr

example code

module main

fn main() {
	x:=(1+2)
	y:=(1<2)
}

ConcatExpr

AST struct

ConcatExpr

example code

a, b, c := match false {
	true { 1, 2, 3 }
	false { 4, 5, 6 }
	else { 7, 8, 9 }
}

Function

FnDecl

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
}

AnonFn

AST struct

AnonFn

example code

module main

fn main() {
	f1 := fn (x int, y int) int {
		return x + y
	}
	f1(1,3)
}

DeferStmt

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

Struct

StructDecl

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

StructInit

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

Assoc(deprecated)

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
}

Interface

AST struct

InterfaceDecl

example code

module main

interface Speaker { //comment 1
	speak() string
	silent()
}

Type

Alias Type

AST struct

AliasTypeDecl

example code

module main

struct Human {
	name string
}
type Myint =  int /*comment 1*/ //comment 2
type Person = Human

Function Type

AST struct

FnTypeDecl

example code

module main

type Mid_fn = fn (int, string) int /*comment 1*/ //comment 2

Sum type

AST struct

SumTypeDecl

example code

module main

struct User {
	name string
	age  int
}

type MySumtype = User | int | string //comment 1

FlowControl

Block

AST struct

Block

example code

fn main() {
	my_fn()
}

fn my_fn() {
	// block
	{
		println('in block')
	}
	// unsafe block
	unsafe {
	}
}

if

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 {
	}
}

match

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

for

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

goto

AST struct

GotoLabel

GotoStmt

example code

fn main() {
	mut i := 0
	a: // goto label
	i++
	if i < 3 {
		goto a
	}
	println(i)
}

Error handle

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
}

Concurrent

ChanInit

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

SelectExpr

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
}

LockExpr

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

GoExpr

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

Unsafe

AST struct

UnsafeExpr

example code

module main

fn main() {
	a := ['a', 'b', 'c']
	p := unsafe { &a[2] } // unsafe expr
	println(p)
}

ASM

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
}

SQL

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

Test

AssertStmt

AST struct

AssertStmt

example code

fn test_abc() {
	x := 1
	assert x == 1
}

Compile time

CompFor

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

C Integration

GlobalDecl

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

HashStmt

AST struct

HashStmt

example code

module main
    
#include <stdio.h> 

#flag -lmysqlclient
#flag linux -I/usr/include/mysql
#include <mysql.h>

fn main() {

}

Likely

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

OffsetOf

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

Comment

AST struct

Comment

example code

module main
/*
multi line comment
multi line comment
*/
// signle line comment
fn main() {
	x := 1 // behind statement comment
}

Other

AtExpr

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

License

MIT

Contributors

pull request is welcome ~