v: add constant folding AST transformation (#11085)

pull/11092/head
Caden Haustein 2021-08-06 20:19:18 +00:00 committed by GitHub
parent ec39e38e14
commit cf0767ad6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 232 additions and 0 deletions

View File

@ -7,6 +7,7 @@ import v.util
import v.ast import v.ast
import v.vmod import v.vmod
import v.checker import v.checker
import v.transformer
import v.parser import v.parser
import v.markused import v.markused
import v.depgraph import v.depgraph
@ -20,6 +21,7 @@ pub:
mut: mut:
pref &pref.Preferences pref &pref.Preferences
checker &checker.Checker checker &checker.Checker
transformer &transformer.Transformer
out_name_c string out_name_c string
out_name_js string out_name_js string
max_nr_errors int = 100 max_nr_errors int = 100
@ -60,6 +62,7 @@ pub fn new_builder(pref &pref.Preferences) Builder {
pref: pref pref: pref
table: table table: table
checker: checker.new_checker(table, pref) checker: checker.new_checker(table, pref)
transformer: transformer.new_transformer(pref)
compiled_dir: compiled_dir compiled_dir: compiled_dir
max_nr_errors: if pref.error_limit > 0 { pref.error_limit } else { 100 } max_nr_errors: if pref.error_limit > 0 { pref.error_limit } else { 100 }
cached_msvc: msvc cached_msvc: msvc
@ -86,6 +89,9 @@ pub fn (mut b Builder) middle_stages() ? {
b.checker.check_files(b.parsed_files) b.checker.check_files(b.parsed_files)
util.timing_measure('CHECK') util.timing_measure('CHECK')
b.print_warnings_and_errors() b.print_warnings_and_errors()
util.timing_start('TRANSFORM')
b.transformer.transform_files(b.parsed_files)
util.timing_measure('TRANSFORM')
// //
b.table.complete_interface_check() b.table.complete_interface_check()
if b.pref.skip_unused { if b.pref.skip_unused {

View File

@ -0,0 +1 @@
int zzz = 579

View File

@ -0,0 +1 @@
579

View File

@ -0,0 +1,4 @@
fn main() {
zzz := 123 + 456
println(zzz)
}

View File

@ -0,0 +1,220 @@
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 {
file := unsafe { ast_files[i] }
t.transform(file)
}
}
pub fn (t Transformer) transform(ast_file &ast.File) {
for mut stmt in ast_file.stmts {
t.stmt(mut stmt)
}
}
fn (t Transformer) stmt(mut node ast.Stmt) {
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 {}
ast.CompFor {}
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 {
expr := t.expr(node.expr)
node = &ast.ExprStmt{
...node
expr: expr
}
}
ast.FnDecl {
for mut stmt in node.stmts {
t.stmt(mut stmt)
}
}
ast.ForCStmt {}
ast.ForInStmt {}
ast.ForStmt {}
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 {}
}
}
fn (t Transformer) expr(node ast.Expr) ast.Expr {
match node {
ast.InfixExpr { return t.infix_expr(node) }
else { return node }
}
}
fn (t Transformer) infix_expr(original ast.InfixExpr) ast.Expr {
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 {
.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 {
.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 {
.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
}
}
else {
return node
}
}
}
else {
return node
}
}
}
else {
return node
}
}
}