-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(gnovm): handle loop variables #2429
base: master
Are you sure you want to change the base?
Changes from all commits
ae8c44e
3c46e27
f4306ed
5cc2494
31b2263
f1d7c3e
492f103
31bbcb6
53c47e5
ffb2e76
e23141c
883cc6a
2931579
6b440e0
e9e4454
ea07aee
59a51d3
c771f9c
b49630e
c3b3edf
e42a561
3892c47
ae9158e
d552d74
30386a8
a6d81ed
f8a0769
ff4224e
7beaf3e
b33736f
def501e
dc05e87
9405775
a93e7c6
df9554f
f6b076f
a26d987
e3ad91f
c9eeed2
b44a4e5
1e04c97
0a5df97
c98af3c
f3e7d61
7313720
9b7fe06
ba5a1b8
315096b
401154f
a36641c
8ed0250
409a92f
e5282fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -669,7 +669,7 @@ | |||||
} | ||||||
} | ||||||
// if dep already in loopfindr, abort. | ||||||
if hasName(dep, loopfindr) { | ||||||
if hasName(loopfindr, dep) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
and remove hasName |
||||||
if _, ok := (*depdecl).(*FuncDecl); ok { | ||||||
// recursive function dependencies | ||||||
// are OK with func decls. | ||||||
|
@@ -2082,15 +2082,25 @@ | |||||
func (m *Machine) PopAsPointer(lx Expr) PointerValue { | ||||||
switch lx := lx.(type) { | ||||||
case *NameExpr: | ||||||
lb := m.LastBlock() | ||||||
return lb.GetPointerTo(m.Store, lx.Path) | ||||||
switch lx.Type { | ||||||
case NameExprTypeNormal: | ||||||
lb := m.LastBlock() | ||||||
return lb.GetPointerTo(m.Store, lx.Path) | ||||||
case NameExprTypeHeapUse: | ||||||
lb := m.LastBlock() | ||||||
return lb.GetPointerToHeapUse(m.Store, lx.Path) | ||||||
case NameExprTypeHeapClosure: | ||||||
panic("should not happen") | ||||||
default: | ||||||
panic("unexpected NameExpr in PopAsPointer") | ||||||
} | ||||||
case *IndexExpr: | ||||||
iv := m.PopValue() | ||||||
xv := m.PopValue() | ||||||
return xv.GetPointerAtIndex(m.Alloc, m.Store, iv) | ||||||
case *SelectorExpr: | ||||||
xv := m.PopValue() | ||||||
return xv.GetPointerTo(m.Alloc, m.Store, lx.Path) | ||||||
return xv.GetPointerToFromTV(m.Alloc, m.Store, lx.Path) | ||||||
case *StarExpr: | ||||||
ptr := m.PopValue().V.(PointerValue) | ||||||
return ptr | ||||||
|
@@ -2317,7 +2327,7 @@ | |||||
//---------------------------------------- | ||||||
// utility | ||||||
|
||||||
func hasName(n Name, ns []Name) bool { | ||||||
func hasName(ns []Name, n Name) bool { | ||||||
for _, n2 := range ns { | ||||||
if n == n2 { | ||||||
return true | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -145,11 +145,26 @@ | |||||||||||
// even after preprocessing. Temporary attributes (e.g. those | ||||||||||||
// for preprocessing) are stored in .data. | ||||||||||||
|
||||||||||||
type GnoAttribute string | ||||||||||||
|
||||||||||||
const ( | ||||||||||||
ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED" | ||||||||||||
ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED" | ||||||||||||
ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" | ||||||||||||
ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" | ||||||||||||
ATTR_IOTA GnoAttribute = "ATTR_IOTA" | ||||||||||||
ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONE" // XXX DELETE | ||||||||||||
ATTR_INJECTED GnoAttribute = "ATTR_INJECTED" | ||||||||||||
ATTR_GOTOLOOP_STMT GnoAttribute = "ATTR_GOTOLOOP_STMT" // XXX delete? | ||||||||||||
ATTR_LOOP_DEFINES GnoAttribute = "ATTR_LOOP_DEFINES" // []Name defined within loops. | ||||||||||||
ATTR_LOOP_USES GnoAttribute = "ATTR_LOOP_USES" // []Name loop defines actually used. | ||||||||||||
) | ||||||||||||
|
||||||||||||
type Attributes struct { | ||||||||||||
Line int | ||||||||||||
Column int | ||||||||||||
Label Name | ||||||||||||
data map[interface{}]interface{} // not persisted | ||||||||||||
data map[GnoAttribute]interface{} // not persisted | ||||||||||||
} | ||||||||||||
|
||||||||||||
func (attr *Attributes) GetLine() int { | ||||||||||||
|
@@ -172,26 +187,36 @@ | |||||||||||
return attr.Label | ||||||||||||
} | ||||||||||||
|
||||||||||||
// XXX I think should be AddLabel instead. | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, as there may only be 1 label; I think SetLabel is good. |
||||||||||||
func (attr *Attributes) SetLabel(label Name) { | ||||||||||||
attr.Label = label | ||||||||||||
} | ||||||||||||
|
||||||||||||
func (attr *Attributes) HasAttribute(key interface{}) bool { | ||||||||||||
func (attr *Attributes) HasAttribute(key GnoAttribute) bool { | ||||||||||||
_, ok := attr.data[key] | ||||||||||||
return ok | ||||||||||||
} | ||||||||||||
|
||||||||||||
func (attr *Attributes) GetAttribute(key interface{}) interface{} { | ||||||||||||
// GnoAttribute must not be user provided / arbitrary, | ||||||||||||
// otherwise will create potential exploits. | ||||||||||||
func (attr *Attributes) GetAttribute(key GnoAttribute) interface{} { | ||||||||||||
return attr.data[key] | ||||||||||||
} | ||||||||||||
|
||||||||||||
func (attr *Attributes) SetAttribute(key interface{}, value interface{}) { | ||||||||||||
func (attr *Attributes) SetAttribute(key GnoAttribute, value interface{}) { | ||||||||||||
if attr.data == nil { | ||||||||||||
attr.data = make(map[interface{}]interface{}) | ||||||||||||
attr.data = make(map[GnoAttribute]interface{}) | ||||||||||||
} | ||||||||||||
attr.data[key] = value | ||||||||||||
} | ||||||||||||
|
||||||||||||
func (attr *Attributes) DelAttribute(key GnoAttribute) { | ||||||||||||
if attr.data == nil { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
panic("should not happen, attribute is expected to be non-empty.") | ||||||||||||
} | ||||||||||||
delete(attr.data, key) | ||||||||||||
} | ||||||||||||
|
||||||||||||
// ---------------------------------------- | ||||||||||||
// Node | ||||||||||||
|
||||||||||||
|
@@ -205,9 +230,10 @@ | |||||||||||
SetColumn(int) | ||||||||||||
GetLabel() Name | ||||||||||||
SetLabel(Name) | ||||||||||||
HasAttribute(key interface{}) bool | ||||||||||||
GetAttribute(key interface{}) interface{} | ||||||||||||
SetAttribute(key interface{}, value interface{}) | ||||||||||||
HasAttribute(key GnoAttribute) bool | ||||||||||||
GetAttribute(key GnoAttribute) interface{} | ||||||||||||
SetAttribute(key GnoAttribute, value interface{}) | ||||||||||||
DelAttribute(key GnoAttribute) | ||||||||||||
} | ||||||||||||
|
||||||||||||
// non-pointer receiver to help make immutable. | ||||||||||||
|
@@ -367,11 +393,22 @@ | |||||||||||
_ Expr = &ConstExpr{} | ||||||||||||
) | ||||||||||||
|
||||||||||||
type NameExprType int | ||||||||||||
|
||||||||||||
const ( | ||||||||||||
NameExprTypeNormal NameExprType = iota // default | ||||||||||||
NameExprTypeDefine // when defining normally | ||||||||||||
NameExprTypeHeapDefine // when defining escaped name in loop | ||||||||||||
NameExprTypeHeapUse // when above used in non-define lhs/rhs | ||||||||||||
NameExprTypeHeapClosure // when closure captures name | ||||||||||||
) | ||||||||||||
|
||||||||||||
type NameExpr struct { | ||||||||||||
Attributes | ||||||||||||
// TODO rename .Path's to .ValuePaths. | ||||||||||||
Path ValuePath // set by preprocessor. | ||||||||||||
Name | ||||||||||||
Type NameExprType | ||||||||||||
} | ||||||||||||
|
||||||||||||
type NameExprs []NameExpr | ||||||||||||
|
@@ -498,8 +535,9 @@ | |||||||||||
type FuncLitExpr struct { | ||||||||||||
Attributes | ||||||||||||
StaticBlock | ||||||||||||
Type FuncTypeExpr // function type | ||||||||||||
Body // function body | ||||||||||||
Type FuncTypeExpr // function type | ||||||||||||
Body // function body | ||||||||||||
HeapCaptures NameExprs // filled in findLoopUses1 | ||||||||||||
} | ||||||||||||
|
||||||||||||
// The preprocessor replaces const expressions | ||||||||||||
|
@@ -580,11 +618,15 @@ | |||||||||||
named := false | ||||||||||||
for i, ftx := range ftxz { | ||||||||||||
if i == 0 { | ||||||||||||
named = ftx.Name != "" | ||||||||||||
if ftx.Name == "" || strings.HasPrefix(string(ftx.Name), ".res_") { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make a |
||||||||||||
named = false | ||||||||||||
} else { | ||||||||||||
named = true | ||||||||||||
} | ||||||||||||
} else { | ||||||||||||
if named && ftx.Name == "" { | ||||||||||||
panic("[]FieldTypeExpr has inconsistent namedness (starts named)") | ||||||||||||
} else if !named && ftx.Name != "" { | ||||||||||||
} else if !named && (ftx.Name != "" || !strings.HasPrefix(string(ftx.Name), ".res_")) { | ||||||||||||
panic("[]FieldTypeExpr has inconsistent namedness (starts unnamed)") | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
@@ -1483,6 +1525,7 @@ | |||||||||||
GetNumNames() uint16 | ||||||||||||
GetParentNode(Store) BlockNode | ||||||||||||
GetPathForName(Store, Name) ValuePath | ||||||||||||
GetBlockNodeForPath(Store, ValuePath) BlockNode | ||||||||||||
GetIsConst(Store, Name) bool | ||||||||||||
GetLocalIndex(Name) (uint16, bool) | ||||||||||||
GetValueRef(Store, Name, bool) *TypedValue | ||||||||||||
|
@@ -1582,6 +1625,7 @@ | |||||||||||
} | ||||||||||||
|
||||||||||||
// Implements BlockNode. | ||||||||||||
// NOTE: Extern names may also be local, if declared later. | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
func (sb *StaticBlock) GetExternNames() (ns []Name) { | ||||||||||||
return sb.Externs // copy? | ||||||||||||
} | ||||||||||||
|
@@ -1623,6 +1667,8 @@ | |||||||||||
} | ||||||||||||
// Register as extern. | ||||||||||||
// NOTE: uverse names are externs too. | ||||||||||||
// NOTE: if a name is later declared in this block later, it is both an | ||||||||||||
// extern name with depth > 1, as well as local name with depth == 1. | ||||||||||||
Comment on lines
+1670
to
+1671
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
if !isFile(sb.GetSource(store)) { | ||||||||||||
sb.GetStaticBlock().addExternName(n) | ||||||||||||
} | ||||||||||||
|
@@ -1651,6 +1697,21 @@ | |||||||||||
panic(fmt.Sprintf("name %s not declared", n)) | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Get the containing block node for node with path relative to this containing block. | ||||||||||||
func (sb *StaticBlock) GetBlockNodeForPath(store Store, path ValuePath) BlockNode { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you replace the code in StaticBlock.GetStaticTypeOfAt with this method? |
||||||||||||
if path.Type != VPBlock { | ||||||||||||
panic("expected block type value path but got " + path.Type.String()) | ||||||||||||
} | ||||||||||||
|
||||||||||||
// NOTE: path.Depth == 1 means it's in bn. | ||||||||||||
var bn BlockNode = sb.GetSource(store) | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
for i := 1; i < int(path.Depth); i++ { | ||||||||||||
bn = bn.GetParentNode(store) | ||||||||||||
} | ||||||||||||
|
||||||||||||
return bn | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Returns whether a name defined here in in ancestry is a const. | ||||||||||||
// This is not the same as whether a name's static type is | ||||||||||||
// untyped -- as in c := a == b, a name may be an untyped non-const. | ||||||||||||
|
@@ -2109,18 +2170,6 @@ | |||||||||||
return i | ||||||||||||
} | ||||||||||||
|
||||||||||||
type GnoAttribute string | ||||||||||||
|
||||||||||||
const ( | ||||||||||||
ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED" | ||||||||||||
ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED" | ||||||||||||
ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE" | ||||||||||||
ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" | ||||||||||||
ATTR_IOTA GnoAttribute = "ATTR_IOTA" | ||||||||||||
ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED" | ||||||||||||
ATTR_INJECTED GnoAttribute = "ATTR_INJECTED" | ||||||||||||
) | ||||||||||||
|
||||||||||||
var rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]+$`) | ||||||||||||
|
||||||||||||
// TODO: consider length restrictions. | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also step on type decl.