1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

newjs: sideeffect, break and escape analysis (W.I.P)

This commit is contained in:
Adel Prokurov 2022-12-14 17:31:25 +05:00
parent 9231661b86
commit 13dbb0ec28
6 changed files with 227 additions and 5 deletions

View File

@ -0,0 +1,34 @@
module analysis
import v.ast
import v.ast.walker
struct HasBreakVisitor {
mut:
has_break bool
}
pub fn has_break(n &ast.Node) bool {
mut v := HasBreakVisitor{has_break: false}
walker.walk(mut v, n)
return v.has_break
}
fn (mut v HasBreakVisitor) visit(node &ast.Node) ! {
if v.has_break {
return
}
if node is ast.Stmt {
match node {
ast.BranchStmt {
if node.kind == .key_break && node.label.len > 0 {
v.has_break = true
return
}
}
else {}
}
}
}

View File

@ -0,0 +1,102 @@
module analysis
import v.ast
import v.ast.walker
pub fn escaping_objects(n &ast.Node) []&ast.Var {
mut v := EscapeAnalysis {
escaping: map[voidptr]bool{}
bottom_scopes: map[voidptr]bool{}
}
walker.walk(mut v, n)
mut list := []&ast.Var{}
for obj, _ in v.escaping {
list << &ast.Var(obj)
}
return list
}
struct EscapeAnalysis {
mut:
escaping map[voidptr]bool
top_scope &ast.Scope = unsafe { nil }
bottom_scopes map[voidptr]bool
}
fn (mut v EscapeAnalysis) visit(node &ast.Node) ! {
match node {
ast.Expr {
if node is ast.PostfixExpr {
if node.op == .amp {
if node.expr is ast.Ident {
mut collector := EscapingObjectCollector {
analysis: unsafe { v }
}
walker.walk(mut collector, &ast.Node(ast.Expr(node.expr)))
}
}
}
}
ast.Stmt {
match node {
ast.FnDecl {
v.bottom_scopes[voidptr(node.scope)] = true
mut collector := EscapingObjectCollector {
analysis: unsafe { v }
}
walker.walk(mut collector, &ast.Node(ast.Stmt(node)))
return
}
ast.ForStmt {
v.bottom_scopes[voidptr(node.scope)] = true
return
}
else {
return
}
}
} else {
return
}
}
}
struct EscapingObjectCollector {
mut:
analysis &EscapeAnalysis
}
fn (mut v EscapingObjectCollector) visit(node &ast.Node) ! {
if node is ast.Expr {
match node {
ast.Ident {
if node.obj is ast.Var {
mut s := node.scope
for unsafe { s != nil } {
if s == v.analysis.top_scope {
v.analysis.escaping[voidptr(unsafe { &node })] = true
break
}
if v.analysis.bottom_scopes[voidptr(s)] {
break
}
s = s.parent
}
}
} else {
}
}
}
}

View File

@ -0,0 +1,39 @@
module analysis
import v.ast
import v.ast.walker
struct HasSideEffectVisitor {
mut:
has_sideeffect bool
}
pub fn has_sideeffect(n &ast.Node) bool {
mut v := HasSideEffectVisitor{has_sideeffect: false}
walker.walk(mut v, n)
return v.has_sideeffect
}
fn (mut v HasSideEffectVisitor) visit(node &ast.Node) ! {
if v.has_sideeffect {
return
}
if node is ast.Expr {
match node {
ast.InfixExpr {
if node.op == .arrow {
v.has_sideeffect = true
return
}
}
ast.CallExpr {
v.has_sideeffect = true
return
}
// todo: overloaded operators can lead to side effects as well?
else {}
}
}
}

View File

@ -0,0 +1,30 @@
module newjs
import strings
import v.ast
import v.token
import v.pref
import v.util
import v.util.version
import v.depgraph
[heap]
struct Expression {
str string
parens bool
}
fn (e &Expression) str() string {
return e.str
}
fn (e &Expression) str_with_parens() string {
if e.parens {
return '(' + e.str + ')'
}
return e.str
}
fn (mut fc FuncContext) translate_expr(expr ast.Expr) &Expression {
return unsafe { nil }
}

View File

@ -7,6 +7,7 @@ import v.pref
import v.util
import v.util.version
import v.depgraph
import analysis
[heap]

View File

@ -107,12 +107,28 @@ fn (mut fc FuncContext) new_variable_with_level(name_ string, mod_level bool) st
return var_name
}
fn (mut fc FuncContext) new_ident(name string, t ast.Type) {
}
/*
fn (mut fc FuncContext) new_ident(name string, t ast.Type) &ast.Ident {
id := &ast.Ident {
language: .js
tok_kind: .name
comptime: false
mod: fc.mod_ctx.mod.name
name: name
kind: .variable
info: IdentVar {
typ: t
is_mut: true
is_static: false
is_volatile: false
is_optional: false
share: .mut_t
}
}
}*/
fn is_mod_level(fc &FuncContext, sym &ast.Ident) bool {
return unsafe { sym.scope is nil || (sym.scope == fc.mod_ctx.gen.table.global_scope || sym.scope.parent == fc.mod_ctx.gen.table.global_scope) }
return unsafe { sym.scope == nil || (sym.scope == fc.mod_ctx.gen.table.global_scope || sym.scope.parent == fc.mod_ctx.gen.table.global_scope) }
}
fn (mut fc FuncContext) ident_name(o &ast.Ident) string {
@ -125,7 +141,7 @@ fn (mut fc FuncContext) ident_name(o &ast.Ident) string {
}
name := fc.mod_ctx.object_names[o] or {
name := fc.new_variable_with_level(o.name, is_mod_level(o))
name := fc.new_variable_with_level(o.name, is_mod_level(fc, o))
fc.mod_ctx.object_names[o] = name
name
}