2021-08-06 22:19:18 +02:00
|
|
|
module transformer
|
|
|
|
|
|
|
|
import v.pref
|
|
|
|
import v.ast
|
|
|
|
|
|
|
|
pub struct Transformer {
|
|
|
|
pref &pref.Preferences
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_transformer(pref &pref.Preferences) &Transformer {
|
|
|
|
return &Transformer{
|
|
|
|
pref: pref
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn (t Transformer) transform_files(ast_files []&ast.File) {
|
|
|
|
for i in 0 .. ast_files.len {
|
2021-10-17 05:41:39 +02:00
|
|
|
mut file := unsafe { ast_files[i] }
|
|
|
|
t.transform(mut file)
|
2021-08-06 22:19:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-17 05:41:39 +02:00
|
|
|
pub fn (t Transformer) transform(mut ast_file ast.File) {
|
2021-08-06 22:19:18 +02:00
|
|
|
for mut stmt in ast_file.stmts {
|
|
|
|
t.stmt(mut stmt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-10 00:55:25 +02:00
|
|
|
pub fn (t Transformer) stmt(mut node ast.Stmt) {
|
2021-08-06 22:19:18 +02:00
|
|
|
match mut node {
|
|
|
|
ast.EmptyStmt {}
|
|
|
|
ast.NodeError {}
|
|
|
|
ast.AsmStmt {}
|
|
|
|
ast.AssertStmt {}
|
|
|
|
ast.AssignStmt {
|
|
|
|
for mut right in node.right {
|
|
|
|
right = t.expr(right)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.Block {
|
|
|
|
for mut stmt in node.stmts {
|
|
|
|
t.stmt(mut stmt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.BranchStmt {}
|
2021-11-17 07:29:43 +01:00
|
|
|
ast.ComptimeFor {}
|
2021-08-06 22:19:18 +02:00
|
|
|
ast.ConstDecl {
|
|
|
|
for mut field in node.fields {
|
|
|
|
expr := t.expr(field.expr)
|
|
|
|
field = ast.ConstField{
|
|
|
|
...(*field)
|
|
|
|
expr: expr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.DeferStmt {}
|
|
|
|
ast.EnumDecl {}
|
|
|
|
ast.ExprStmt {
|
2021-10-14 01:15:52 +02:00
|
|
|
expr := node.expr
|
|
|
|
node = &ast.ExprStmt{
|
|
|
|
...node
|
|
|
|
expr: match mut expr {
|
|
|
|
ast.IfExpr {
|
|
|
|
t.if_expr(mut expr)
|
|
|
|
}
|
|
|
|
ast.MatchExpr {
|
|
|
|
t.match_expr(mut expr)
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
t.expr(expr)
|
|
|
|
}
|
2021-10-11 13:29:17 +02:00
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.FnDecl {
|
|
|
|
for mut stmt in node.stmts {
|
|
|
|
t.stmt(mut stmt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.ForCStmt {}
|
|
|
|
ast.ForInStmt {}
|
2021-10-11 13:29:17 +02:00
|
|
|
ast.ForStmt {
|
|
|
|
node = &ast.ForStmt{
|
|
|
|
...node
|
|
|
|
cond: t.expr(node.cond)
|
|
|
|
}
|
|
|
|
if node.cond is ast.BoolLiteral && !(node.cond as ast.BoolLiteral).val { // for false { ... } should be eleminated
|
|
|
|
node = &ast.EmptyStmt{}
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
ast.GlobalDecl {}
|
|
|
|
ast.GotoLabel {}
|
|
|
|
ast.GotoStmt {}
|
|
|
|
ast.HashStmt {}
|
|
|
|
ast.Import {}
|
|
|
|
ast.InterfaceDecl {}
|
|
|
|
ast.Module {}
|
|
|
|
ast.Return {
|
|
|
|
for mut expr in node.exprs {
|
|
|
|
expr = t.expr(expr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.SqlStmt {}
|
|
|
|
ast.StructDecl {}
|
|
|
|
ast.TypeDecl {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-10 00:55:25 +02:00
|
|
|
pub fn (t Transformer) expr(node ast.Expr) ast.Expr {
|
2021-10-11 13:29:17 +02:00
|
|
|
match mut node {
|
|
|
|
ast.InfixExpr {
|
|
|
|
return t.infix_expr(node)
|
|
|
|
}
|
|
|
|
ast.IndexExpr {
|
|
|
|
return ast.IndexExpr{
|
|
|
|
...node
|
|
|
|
index: t.expr(node.index)
|
|
|
|
}
|
|
|
|
}
|
2021-10-14 01:15:52 +02:00
|
|
|
ast.IfExpr {
|
|
|
|
for mut branch in node.branches {
|
|
|
|
branch = ast.IfBranch{
|
|
|
|
...(*branch)
|
|
|
|
cond: t.expr(branch.cond)
|
|
|
|
}
|
|
|
|
for i, mut stmt in branch.stmts {
|
|
|
|
t.stmt(mut stmt)
|
|
|
|
|
|
|
|
if i == branch.stmts.len - 1 {
|
|
|
|
if stmt is ast.ExprStmt {
|
|
|
|
expr := (stmt as ast.ExprStmt).expr
|
|
|
|
|
|
|
|
match expr {
|
|
|
|
ast.IfExpr {
|
|
|
|
if expr.branches.len == 1 {
|
|
|
|
branch.stmts.pop()
|
|
|
|
branch.stmts << expr.branches[0].stmts
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.MatchExpr {
|
|
|
|
if expr.branches.len == 1 {
|
|
|
|
branch.stmts.pop()
|
|
|
|
branch.stmts << expr.branches[0].stmts
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return node
|
|
|
|
}
|
2021-10-11 13:29:17 +02:00
|
|
|
ast.MatchExpr {
|
2021-10-14 01:15:52 +02:00
|
|
|
node = ast.MatchExpr{
|
|
|
|
...node
|
|
|
|
cond: t.expr(node.cond)
|
|
|
|
}
|
2021-10-11 13:29:17 +02:00
|
|
|
for mut branch in node.branches {
|
2021-10-14 01:15:52 +02:00
|
|
|
for mut expr in branch.exprs {
|
|
|
|
expr = t.expr(expr)
|
|
|
|
}
|
|
|
|
for i, mut stmt in branch.stmts {
|
2021-10-11 13:29:17 +02:00
|
|
|
t.stmt(mut stmt)
|
2021-10-14 01:15:52 +02:00
|
|
|
|
|
|
|
if i == branch.stmts.len - 1 {
|
|
|
|
if stmt is ast.ExprStmt {
|
|
|
|
expr := (stmt as ast.ExprStmt).expr
|
|
|
|
|
|
|
|
match expr {
|
|
|
|
ast.IfExpr {
|
|
|
|
if expr.branches.len == 1 {
|
|
|
|
branch.stmts.pop()
|
|
|
|
branch.stmts << expr.branches[0].stmts
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.MatchExpr {
|
|
|
|
if expr.branches.len == 1 {
|
|
|
|
branch.stmts.pop()
|
|
|
|
branch.stmts << expr.branches[0].stmts
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-11 13:29:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 13:29:17 +02:00
|
|
|
pub fn (t Transformer) if_expr(mut original ast.IfExpr) ast.Expr {
|
|
|
|
mut stop_index, mut unreachable_branches := -1, []int{cap: original.branches.len}
|
2021-10-14 01:15:52 +02:00
|
|
|
if original.is_comptime {
|
|
|
|
return *original
|
|
|
|
}
|
2021-10-11 13:29:17 +02:00
|
|
|
for i, mut branch in original.branches {
|
|
|
|
for mut stmt in branch.stmts {
|
|
|
|
t.stmt(mut stmt)
|
|
|
|
}
|
|
|
|
cond := t.expr(branch.cond)
|
|
|
|
branch = ast.IfBranch{
|
|
|
|
...(*branch)
|
|
|
|
cond: cond
|
|
|
|
}
|
|
|
|
if cond is ast.BoolLiteral {
|
|
|
|
if cond.val { // eliminates remaining branches when reached first bool literal `true`
|
|
|
|
stop_index = i
|
|
|
|
break
|
|
|
|
} else { // discard unreachable branch when reached bool literal `false`
|
|
|
|
unreachable_branches << i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if stop_index != -1 {
|
|
|
|
unreachable_branches = unreachable_branches.filter(it < stop_index)
|
|
|
|
original.branches = original.branches[..stop_index + 1]
|
|
|
|
}
|
|
|
|
for unreachable_branches.len != 0 {
|
|
|
|
original.branches.delete(unreachable_branches.pop())
|
|
|
|
}
|
|
|
|
if original.branches.len == 0 { // no remain branches to walk through
|
|
|
|
return ast.EmptyExpr{}
|
|
|
|
}
|
|
|
|
if original.branches.len == 1 && original.branches[0].cond.type_name() == 'unknown v.ast.Expr' {
|
|
|
|
original.branches[0] = &ast.IfBranch{
|
|
|
|
...original.branches[0]
|
|
|
|
cond: ast.BoolLiteral{
|
|
|
|
val: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *original
|
|
|
|
}
|
|
|
|
|
2021-10-14 01:15:52 +02:00
|
|
|
pub fn (t Transformer) match_expr(mut original ast.MatchExpr) ast.Expr {
|
|
|
|
cond, mut terminate := t.expr(original.cond), false
|
|
|
|
original = ast.MatchExpr{
|
|
|
|
...(*original)
|
|
|
|
cond: cond
|
|
|
|
}
|
|
|
|
for mut branch in original.branches {
|
|
|
|
if branch.is_else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for mut stmt in branch.stmts {
|
|
|
|
t.stmt(mut stmt)
|
|
|
|
}
|
|
|
|
|
|
|
|
for mut expr in branch.exprs {
|
|
|
|
expr = t.expr(expr)
|
|
|
|
|
|
|
|
match cond {
|
|
|
|
ast.BoolLiteral {
|
|
|
|
if expr is ast.BoolLiteral {
|
|
|
|
if cond.val == (expr as ast.BoolLiteral).val {
|
|
|
|
branch.exprs = [expr]
|
|
|
|
original = ast.MatchExpr{
|
|
|
|
...(*original)
|
|
|
|
branches: [branch]
|
|
|
|
}
|
|
|
|
terminate = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.IntegerLiteral {
|
|
|
|
if expr is ast.IntegerLiteral {
|
|
|
|
if cond.val.int() == (expr as ast.IntegerLiteral).val.int() {
|
|
|
|
branch.exprs = [expr]
|
|
|
|
original = ast.MatchExpr{
|
|
|
|
...(*original)
|
|
|
|
branches: [branch]
|
|
|
|
}
|
|
|
|
terminate = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.FloatLiteral {
|
|
|
|
if expr is ast.FloatLiteral {
|
|
|
|
if cond.val.f32() == (expr as ast.FloatLiteral).val.f32() {
|
|
|
|
branch.exprs = [expr]
|
|
|
|
original = ast.MatchExpr{
|
|
|
|
...(*original)
|
|
|
|
branches: [branch]
|
|
|
|
}
|
|
|
|
terminate = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.StringLiteral {
|
|
|
|
if expr is ast.StringLiteral {
|
|
|
|
if cond.val == (expr as ast.StringLiteral).val {
|
|
|
|
branch.exprs = [expr]
|
|
|
|
original = ast.MatchExpr{
|
|
|
|
...(*original)
|
|
|
|
branches: [branch]
|
|
|
|
}
|
|
|
|
terminate = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if terminate {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return *original
|
|
|
|
}
|
|
|
|
|
2021-10-10 00:55:25 +02:00
|
|
|
pub fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
|
2021-08-06 22:19:18 +02:00
|
|
|
mut node := original
|
|
|
|
node.left = t.expr(node.left)
|
|
|
|
node.right = t.expr(node.right)
|
|
|
|
mut pos := node.left.position()
|
|
|
|
pos.extend(node.pos)
|
|
|
|
pos.extend(node.right.position())
|
|
|
|
left_node := node.left
|
|
|
|
right_node := node.right
|
|
|
|
match left_node {
|
|
|
|
ast.BoolLiteral {
|
|
|
|
match right_node {
|
|
|
|
ast.BoolLiteral {
|
|
|
|
match node.op {
|
2021-10-11 13:29:17 +02:00
|
|
|
.eq {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val == right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.ne {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val != right_node.val
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
.and {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val && right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.logical_or {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val || right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.StringLiteral {
|
|
|
|
match right_node {
|
|
|
|
ast.StringLiteral {
|
|
|
|
match node.op {
|
2021-10-11 13:29:17 +02:00
|
|
|
.eq {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val == right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.ne {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val != right_node.val
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
.plus {
|
|
|
|
return ast.StringLiteral{
|
|
|
|
val: left_node.val + right_node.val
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast.IntegerLiteral {
|
|
|
|
match right_node {
|
|
|
|
ast.IntegerLiteral {
|
|
|
|
left_val := left_node.val.int()
|
|
|
|
right_val := right_node.val.int()
|
|
|
|
match node.op {
|
2021-10-11 13:29:17 +02:00
|
|
|
.eq {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val == right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.ne {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val != right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.gt {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val > right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.ge {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val >= right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.lt {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val < right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.le {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val <= right_node.val
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
.plus {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val + right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.mul {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val * right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.minus {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val - right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.div {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val / right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.mod {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val % right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.xor {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val ^ right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.pipe {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val | right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.amp {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val & right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
2021-10-11 13:29:17 +02:00
|
|
|
.left_shift {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val << right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.right_shift {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val >> right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.unsigned_right_shift {
|
|
|
|
return ast.IntegerLiteral{
|
|
|
|
val: (left_val >>> right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-14 01:15:52 +02:00
|
|
|
ast.FloatLiteral {
|
|
|
|
match right_node {
|
|
|
|
ast.FloatLiteral {
|
|
|
|
left_val := left_node.val.f32()
|
|
|
|
right_val := right_node.val.f32()
|
|
|
|
match node.op {
|
|
|
|
.eq {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val == right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.ne {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val != right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.gt {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val > right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.ge {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val >= right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.lt {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val < right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.le {
|
|
|
|
return ast.BoolLiteral{
|
|
|
|
val: left_node.val <= right_node.val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.plus {
|
|
|
|
return ast.FloatLiteral{
|
|
|
|
val: (left_val + right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.mul {
|
|
|
|
return ast.FloatLiteral{
|
|
|
|
val: (left_val * right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.minus {
|
|
|
|
return ast.FloatLiteral{
|
|
|
|
val: (left_val - right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.div {
|
|
|
|
return ast.FloatLiteral{
|
|
|
|
val: (left_val / right_val).str()
|
|
|
|
pos: pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-06 22:19:18 +02:00
|
|
|
else {
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|