lang: ast, gapi, interfaces, parser: Print line numbers on error
This adds an initial implementation of printing line numbers on type unification errors. It also attempts to print a visual position indicator for most scenarios. This patch was started by Felix Frank and finished by James Shubin. Co-authored-by: Felix Frank <Felix.Frank.de@gmail.com>
This commit is contained in:
@@ -180,6 +180,9 @@ var (
|
|||||||
// StmtBind is a representation of an assignment, which binds a variable to an
|
// StmtBind is a representation of an assignment, which binds a variable to an
|
||||||
// expression.
|
// expression.
|
||||||
type StmtBind struct {
|
type StmtBind struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Ident string
|
Ident string
|
||||||
Value interfaces.Expr
|
Value interfaces.Expr
|
||||||
Type *types.Type
|
Type *types.Type
|
||||||
@@ -205,6 +208,9 @@ func (obj *StmtBind) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtBind) Init(data *interfaces.Data) error {
|
func (obj *StmtBind) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Ident == "" {
|
if obj.Ident == "" {
|
||||||
return fmt.Errorf("bind ident is empty")
|
return fmt.Errorf("bind ident is empty")
|
||||||
}
|
}
|
||||||
@@ -221,6 +227,8 @@ func (obj *StmtBind) Interpolate() (interfaces.Stmt, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &StmtBind{
|
return &StmtBind{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Ident: obj.Ident,
|
Ident: obj.Ident,
|
||||||
Value: interpolated,
|
Value: interpolated,
|
||||||
Type: obj.Type,
|
Type: obj.Type,
|
||||||
@@ -242,6 +250,8 @@ func (obj *StmtBind) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtBind{
|
return &StmtBind{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Ident: obj.Ident,
|
Ident: obj.Ident,
|
||||||
Value: value,
|
Value: value,
|
||||||
Type: obj.Type,
|
Type: obj.Type,
|
||||||
@@ -319,6 +329,7 @@ func (obj *StmtBind) TypeCheck() ([]*interfaces.UnificationInvariant, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Value,
|
Expr: obj.Value,
|
||||||
Expect: typExpr, // obj.Type
|
Expect: typExpr, // obj.Type
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -359,6 +370,7 @@ func (obj *StmtBind) Output(map[interfaces.Func]types.Value) (*interfaces.Output
|
|||||||
// TODO: Consider expanding Name to have this return a list of Res's in the
|
// TODO: Consider expanding Name to have this return a list of Res's in the
|
||||||
// Output function if it is a map[name]struct{}, or even a map[[]name]struct{}.
|
// Output function if it is a map[name]struct{}, or even a map[[]name]struct{}.
|
||||||
type StmtRes struct {
|
type StmtRes struct {
|
||||||
|
Textarea
|
||||||
data *interfaces.Data
|
data *interfaces.Data
|
||||||
|
|
||||||
Kind string // kind of resource, eg: pkg, file, svc, etc...
|
Kind string // kind of resource, eg: pkg, file, svc, etc...
|
||||||
@@ -393,6 +405,9 @@ func (obj *StmtRes) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtRes) Init(data *interfaces.Data) error {
|
func (obj *StmtRes) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Kind == "" {
|
if obj.Kind == "" {
|
||||||
return fmt.Errorf("res kind is empty")
|
return fmt.Errorf("res kind is empty")
|
||||||
}
|
}
|
||||||
@@ -401,7 +416,6 @@ func (obj *StmtRes) Init(data *interfaces.Data) error {
|
|||||||
return fmt.Errorf("kind must not contain underscores")
|
return fmt.Errorf("kind must not contain underscores")
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.data = data
|
|
||||||
if err := obj.Name.Init(data); err != nil {
|
if err := obj.Name.Init(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -457,6 +471,7 @@ func (obj *StmtRes) Interpolate() (interfaces.Stmt, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &StmtRes{
|
return &StmtRes{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
Kind: obj.Kind,
|
Kind: obj.Kind,
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -497,6 +512,7 @@ func (obj *StmtRes) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtRes{
|
return &StmtRes{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
Kind: obj.Kind,
|
Kind: obj.Kind,
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -628,6 +644,7 @@ func (obj *StmtRes) TypeCheck() ([]*interfaces.UnificationInvariant, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Name,
|
Expr: obj.Name,
|
||||||
Expect: typExpr, // the name
|
Expect: typExpr, // the name
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -1201,6 +1218,9 @@ type StmtResContents interface {
|
|||||||
// StmtResField represents a single field in the parsed resource representation.
|
// StmtResField represents a single field in the parsed resource representation.
|
||||||
// This does not satisfy the Stmt interface.
|
// This does not satisfy the Stmt interface.
|
||||||
type StmtResField struct {
|
type StmtResField struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Field string
|
Field string
|
||||||
Value interfaces.Expr
|
Value interfaces.Expr
|
||||||
valuePtr interfaces.Func // ptr for table lookup
|
valuePtr interfaces.Func // ptr for table lookup
|
||||||
@@ -1234,6 +1254,9 @@ func (obj *StmtResField) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtResField) Init(data *interfaces.Data) error {
|
func (obj *StmtResField) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Field == "" {
|
if obj.Field == "" {
|
||||||
return fmt.Errorf("res field name is empty")
|
return fmt.Errorf("res field name is empty")
|
||||||
}
|
}
|
||||||
@@ -1264,6 +1287,8 @@ func (obj *StmtResField) Interpolate() (StmtResContents, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &StmtResField{
|
return &StmtResField{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Field: obj.Field,
|
Field: obj.Field,
|
||||||
Value: interpolated,
|
Value: interpolated,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -1297,6 +1322,8 @@ func (obj *StmtResField) Copy() (StmtResContents, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtResField{
|
return &StmtResField{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Field: obj.Field,
|
Field: obj.Field,
|
||||||
Value: value,
|
Value: value,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -1388,6 +1415,7 @@ func (obj *StmtResField) TypeCheck(kind string) ([]*interfaces.UnificationInvari
|
|||||||
|
|
||||||
// XXX: Is this needed?
|
// XXX: Is this needed?
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Condition,
|
Expr: obj.Condition,
|
||||||
Expect: types.TypeBool,
|
Expect: types.TypeBool,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -1428,6 +1456,7 @@ func (obj *StmtResField) TypeCheck(kind string) ([]*interfaces.UnificationInvari
|
|||||||
|
|
||||||
// regular scenario
|
// regular scenario
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Value,
|
Expr: obj.Value,
|
||||||
Expect: typExpr,
|
Expect: typExpr,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -1474,6 +1503,9 @@ func (obj *StmtResField) Graph() (*pgraph.Graph, error) {
|
|||||||
// StmtResEdge represents a single edge property in the parsed resource
|
// StmtResEdge represents a single edge property in the parsed resource
|
||||||
// representation. This does not satisfy the Stmt interface.
|
// representation. This does not satisfy the Stmt interface.
|
||||||
type StmtResEdge struct {
|
type StmtResEdge struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Property string // TODO: iota constant instead?
|
Property string // TODO: iota constant instead?
|
||||||
EdgeHalf *StmtEdgeHalf
|
EdgeHalf *StmtEdgeHalf
|
||||||
Condition interfaces.Expr // the value will be used if nil or true
|
Condition interfaces.Expr // the value will be used if nil or true
|
||||||
@@ -1506,6 +1538,9 @@ func (obj *StmtResEdge) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtResEdge) Init(data *interfaces.Data) error {
|
func (obj *StmtResEdge) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Property == "" {
|
if obj.Property == "" {
|
||||||
return fmt.Errorf("res edge property is empty")
|
return fmt.Errorf("res edge property is empty")
|
||||||
}
|
}
|
||||||
@@ -1539,6 +1574,8 @@ func (obj *StmtResEdge) Interpolate() (StmtResContents, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &StmtResEdge{
|
return &StmtResEdge{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Property: obj.Property,
|
Property: obj.Property,
|
||||||
EdgeHalf: interpolated,
|
EdgeHalf: interpolated,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -1571,6 +1608,8 @@ func (obj *StmtResEdge) Copy() (StmtResContents, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtResEdge{
|
return &StmtResEdge{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Property: obj.Property,
|
Property: obj.Property,
|
||||||
EdgeHalf: edgeHalf,
|
EdgeHalf: edgeHalf,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -1663,6 +1702,7 @@ func (obj *StmtResEdge) TypeCheck(kind string) ([]*interfaces.UnificationInvaria
|
|||||||
|
|
||||||
// XXX: Is this needed?
|
// XXX: Is this needed?
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Condition,
|
Expr: obj.Condition,
|
||||||
Expect: types.TypeBool,
|
Expect: types.TypeBool,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -1713,6 +1753,9 @@ func (obj *StmtResEdge) Graph() (*pgraph.Graph, error) {
|
|||||||
// correspond to the particular meta parameter specified. This does not satisfy
|
// correspond to the particular meta parameter specified. This does not satisfy
|
||||||
// the Stmt interface.
|
// the Stmt interface.
|
||||||
type StmtResMeta struct {
|
type StmtResMeta struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Property string // TODO: iota constant instead?
|
Property string // TODO: iota constant instead?
|
||||||
MetaExpr interfaces.Expr
|
MetaExpr interfaces.Expr
|
||||||
metaExprPtr interfaces.Func // ptr for table lookup
|
metaExprPtr interfaces.Func // ptr for table lookup
|
||||||
@@ -1746,6 +1789,9 @@ func (obj *StmtResMeta) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtResMeta) Init(data *interfaces.Data) error {
|
func (obj *StmtResMeta) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Property == "" {
|
if obj.Property == "" {
|
||||||
return fmt.Errorf("res meta property is empty")
|
return fmt.Errorf("res meta property is empty")
|
||||||
}
|
}
|
||||||
@@ -1799,6 +1845,8 @@ func (obj *StmtResMeta) Interpolate() (StmtResContents, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &StmtResMeta{
|
return &StmtResMeta{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Property: obj.Property,
|
Property: obj.Property,
|
||||||
MetaExpr: interpolated,
|
MetaExpr: interpolated,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -1831,6 +1879,8 @@ func (obj *StmtResMeta) Copy() (StmtResContents, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtResMeta{
|
return &StmtResMeta{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Property: obj.Property,
|
Property: obj.Property,
|
||||||
MetaExpr: metaExpr,
|
MetaExpr: metaExpr,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -1924,6 +1974,7 @@ func (obj *StmtResMeta) TypeCheck(kind string) ([]*interfaces.UnificationInvaria
|
|||||||
|
|
||||||
// XXX: Is this needed?
|
// XXX: Is this needed?
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Condition,
|
Expr: obj.Condition,
|
||||||
Expect: types.TypeBool,
|
Expect: types.TypeBool,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -2002,6 +2053,7 @@ func (obj *StmtResMeta) TypeCheck(kind string) ([]*interfaces.UnificationInvaria
|
|||||||
}
|
}
|
||||||
|
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.MetaExpr,
|
Expr: obj.MetaExpr,
|
||||||
Expect: typExpr,
|
Expect: typExpr,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -2055,6 +2107,9 @@ func (obj *StmtResMeta) Graph() (*pgraph.Graph, error) {
|
|||||||
// names are compatible and listed. In this case of Send/Recv, only lists of
|
// names are compatible and listed. In this case of Send/Recv, only lists of
|
||||||
// length two are legal.
|
// length two are legal.
|
||||||
type StmtEdge struct {
|
type StmtEdge struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
EdgeHalfList []*StmtEdgeHalf // represents a chain of edges
|
EdgeHalfList []*StmtEdgeHalf // represents a chain of edges
|
||||||
|
|
||||||
// TODO: should notify be an Expr?
|
// TODO: should notify be an Expr?
|
||||||
@@ -2083,6 +2138,9 @@ func (obj *StmtEdge) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtEdge) Init(data *interfaces.Data) error {
|
func (obj *StmtEdge) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
for _, x := range obj.EdgeHalfList {
|
for _, x := range obj.EdgeHalfList {
|
||||||
if err := x.Init(data); err != nil {
|
if err := x.Init(data); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -2109,6 +2167,8 @@ func (obj *StmtEdge) Interpolate() (interfaces.Stmt, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &StmtEdge{
|
return &StmtEdge{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
EdgeHalfList: edgeHalfList,
|
EdgeHalfList: edgeHalfList,
|
||||||
Notify: obj.Notify,
|
Notify: obj.Notify,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -2133,6 +2193,8 @@ func (obj *StmtEdge) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtEdge{
|
return &StmtEdge{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
EdgeHalfList: edgeHalfList,
|
EdgeHalfList: edgeHalfList,
|
||||||
Notify: obj.Notify,
|
Notify: obj.Notify,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -2394,6 +2456,9 @@ func (obj *StmtEdge) Output(table map[interfaces.Func]types.Value) (*interfaces.
|
|||||||
// is assumed that a list of strings should be expected. More mechanisms to
|
// is assumed that a list of strings should be expected. More mechanisms to
|
||||||
// determine if the value is static may be added over time.
|
// determine if the value is static may be added over time.
|
||||||
type StmtEdgeHalf struct {
|
type StmtEdgeHalf struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Kind string // kind of resource, eg: pkg, file, svc, etc...
|
Kind string // kind of resource, eg: pkg, file, svc, etc...
|
||||||
Name interfaces.Expr // unique name for the res of this kind
|
Name interfaces.Expr // unique name for the res of this kind
|
||||||
namePtr interfaces.Func // ptr for table lookup
|
namePtr interfaces.Func // ptr for table lookup
|
||||||
@@ -2421,6 +2486,8 @@ func (obj *StmtEdgeHalf) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtEdgeHalf) Init(data *interfaces.Data) error {
|
func (obj *StmtEdgeHalf) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
if obj.Kind == "" {
|
if obj.Kind == "" {
|
||||||
return fmt.Errorf("edge half kind is empty")
|
return fmt.Errorf("edge half kind is empty")
|
||||||
}
|
}
|
||||||
@@ -2443,6 +2510,7 @@ func (obj *StmtEdgeHalf) Interpolate() (*StmtEdgeHalf, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &StmtEdgeHalf{
|
return &StmtEdgeHalf{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
Kind: obj.Kind,
|
Kind: obj.Kind,
|
||||||
Name: name,
|
Name: name,
|
||||||
SendRecv: obj.SendRecv,
|
SendRecv: obj.SendRecv,
|
||||||
@@ -2464,6 +2532,7 @@ func (obj *StmtEdgeHalf) Copy() (*StmtEdgeHalf, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtEdgeHalf{
|
return &StmtEdgeHalf{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
Kind: obj.Kind,
|
Kind: obj.Kind,
|
||||||
Name: name,
|
Name: name,
|
||||||
SendRecv: obj.SendRecv,
|
SendRecv: obj.SendRecv,
|
||||||
@@ -2523,6 +2592,7 @@ func (obj *StmtEdgeHalf) TypeCheck() ([]*interfaces.UnificationInvariant, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Name,
|
Expr: obj.Name,
|
||||||
Expect: typExpr, // the name
|
Expect: typExpr, // the name
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -2557,6 +2627,9 @@ func (obj *StmtEdgeHalf) Graph() (*pgraph.Graph, error) {
|
|||||||
// optional, it is the else branch, although this struct allows either to be
|
// optional, it is the else branch, although this struct allows either to be
|
||||||
// optional, even if it is not commonly used.
|
// optional, even if it is not commonly used.
|
||||||
type StmtIf struct {
|
type StmtIf struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Condition interfaces.Expr
|
Condition interfaces.Expr
|
||||||
conditionPtr interfaces.Func // ptr for table lookup
|
conditionPtr interfaces.Func // ptr for table lookup
|
||||||
ThenBranch interfaces.Stmt // optional, but usually present
|
ThenBranch interfaces.Stmt // optional, but usually present
|
||||||
@@ -2604,6 +2677,9 @@ func (obj *StmtIf) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtIf) Init(data *interfaces.Data) error {
|
func (obj *StmtIf) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if err := obj.Condition.Init(data); err != nil {
|
if err := obj.Condition.Init(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -2643,6 +2719,8 @@ func (obj *StmtIf) Interpolate() (interfaces.Stmt, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &StmtIf{
|
return &StmtIf{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
ThenBranch: thenBranch,
|
ThenBranch: thenBranch,
|
||||||
ElseBranch: elseBranch,
|
ElseBranch: elseBranch,
|
||||||
@@ -2685,6 +2763,8 @@ func (obj *StmtIf) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtIf{
|
return &StmtIf{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
ThenBranch: thenBranch,
|
ThenBranch: thenBranch,
|
||||||
ElseBranch: elseBranch,
|
ElseBranch: elseBranch,
|
||||||
@@ -2807,6 +2887,7 @@ func (obj *StmtIf) TypeCheck() ([]*interfaces.UnificationInvariant, error) {
|
|||||||
|
|
||||||
typExpr := types.TypeBool // default
|
typExpr := types.TypeBool // default
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Condition,
|
Expr: obj.Condition,
|
||||||
Expect: typExpr, // the condition
|
Expect: typExpr, // the condition
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -2915,6 +2996,7 @@ func (obj *StmtIf) Output(table map[interfaces.Func]types.Value) (*interfaces.Ou
|
|||||||
// the bind statement's are correctly applied in this scope, and irrespective of
|
// the bind statement's are correctly applied in this scope, and irrespective of
|
||||||
// their order of definition.
|
// their order of definition.
|
||||||
type StmtProg struct {
|
type StmtProg struct {
|
||||||
|
Textarea
|
||||||
data *interfaces.Data
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for use by imports
|
scope *interfaces.Scope // store for use by imports
|
||||||
|
|
||||||
@@ -3038,6 +3120,7 @@ func (obj *StmtProg) Interpolate() (interfaces.Stmt, error) {
|
|||||||
body = append(body, interpolated)
|
body = append(body, interpolated)
|
||||||
}
|
}
|
||||||
return &StmtProg{
|
return &StmtProg{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
importProgs: obj.importProgs, // TODO: do we even need this here?
|
importProgs: obj.importProgs, // TODO: do we even need this here?
|
||||||
@@ -3065,6 +3148,7 @@ func (obj *StmtProg) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtProg{
|
return &StmtProg{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
importProgs: obj.importProgs, // TODO: do we even need this here?
|
importProgs: obj.importProgs, // TODO: do we even need this here?
|
||||||
@@ -3646,6 +3730,7 @@ func (obj *StmtProg) importScopeWithParsedInputs(input *inputs.ParsedInput, scop
|
|||||||
LexParser: obj.data.LexParser,
|
LexParser: obj.data.LexParser,
|
||||||
Downloader: obj.data.Downloader,
|
Downloader: obj.data.Downloader,
|
||||||
StrInterpolater: obj.data.StrInterpolater,
|
StrInterpolater: obj.data.StrInterpolater,
|
||||||
|
SourceFinder: obj.data.SourceFinder,
|
||||||
//World: obj.data.World, // TODO: do we need this?
|
//World: obj.data.World, // TODO: do we need this?
|
||||||
|
|
||||||
//Prefix: obj.Prefix, // TODO: add a path on?
|
//Prefix: obj.Prefix, // TODO: add a path on?
|
||||||
@@ -4326,6 +4411,9 @@ func (obj *StmtProg) IsModuleUnsafe() error { // TODO: rename this function?
|
|||||||
// the supplied function in the current scope and irrespective of the order of
|
// the supplied function in the current scope and irrespective of the order of
|
||||||
// definition.
|
// definition.
|
||||||
type StmtFunc struct {
|
type StmtFunc struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
Func interfaces.Expr
|
Func interfaces.Expr
|
||||||
Type *types.Type
|
Type *types.Type
|
||||||
@@ -4351,11 +4439,13 @@ func (obj *StmtFunc) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtFunc) Init(data *interfaces.Data) error {
|
func (obj *StmtFunc) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Name == "" {
|
if obj.Name == "" {
|
||||||
return fmt.Errorf("func name is empty")
|
return fmt.Errorf("func name is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
//obj.data = data // TODO: ???
|
|
||||||
if err := obj.Func.Init(data); err != nil {
|
if err := obj.Func.Init(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -4373,6 +4463,8 @@ func (obj *StmtFunc) Interpolate() (interfaces.Stmt, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &StmtFunc{
|
return &StmtFunc{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
Func: interpolated,
|
Func: interpolated,
|
||||||
Type: obj.Type,
|
Type: obj.Type,
|
||||||
@@ -4394,6 +4486,8 @@ func (obj *StmtFunc) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtFunc{
|
return &StmtFunc{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
Func: fn,
|
Func: fn,
|
||||||
Type: obj.Type,
|
Type: obj.Type,
|
||||||
@@ -4487,6 +4581,7 @@ func (obj *StmtFunc) TypeCheck() ([]*interfaces.UnificationInvariant, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.Func,
|
Expr: obj.Func,
|
||||||
Expect: typExpr, // obj.Type
|
Expect: typExpr, // obj.Type
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -4530,6 +4625,8 @@ func (obj *StmtFunc) Output(map[interfaces.Func]types.Value) (*interfaces.Output
|
|||||||
// TODO: We don't currently support defining polymorphic classes (eg: different
|
// TODO: We don't currently support defining polymorphic classes (eg: different
|
||||||
// signatures for the same class name) but it might be something to consider.
|
// signatures for the same class name) but it might be something to consider.
|
||||||
type StmtClass struct {
|
type StmtClass struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
@@ -4557,6 +4654,9 @@ func (obj *StmtClass) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtClass) Init(data *interfaces.Data) error {
|
func (obj *StmtClass) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Name == "" {
|
if obj.Name == "" {
|
||||||
return fmt.Errorf("class name is empty")
|
return fmt.Errorf("class name is empty")
|
||||||
}
|
}
|
||||||
@@ -4579,6 +4679,8 @@ func (obj *StmtClass) Interpolate() (interfaces.Stmt, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &StmtClass{
|
return &StmtClass{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
Args: args, // ensure this has length == 0 instead of nil
|
Args: args, // ensure this has length == 0 instead of nil
|
||||||
@@ -4606,6 +4708,8 @@ func (obj *StmtClass) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtClass{
|
return &StmtClass{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
Args: args, // ensure this has length == 0 instead of nil
|
Args: args, // ensure this has length == 0 instead of nil
|
||||||
@@ -4731,6 +4835,9 @@ func (obj *StmtClass) Output(table map[interfaces.Func]types.Value) (*interfaces
|
|||||||
// to call a class except that it produces output instead of a value. Most of
|
// to call a class except that it produces output instead of a value. Most of
|
||||||
// the interesting logic for classes happens here or in StmtProg.
|
// the interesting logic for classes happens here or in StmtProg.
|
||||||
type StmtInclude struct {
|
type StmtInclude struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
class *StmtClass // copy of class that we're using
|
class *StmtClass // copy of class that we're using
|
||||||
orig *StmtInclude // original pointer to this
|
orig *StmtInclude // original pointer to this
|
||||||
|
|
||||||
@@ -4770,6 +4877,9 @@ func (obj *StmtInclude) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtInclude) Init(data *interfaces.Data) error {
|
func (obj *StmtInclude) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Name == "" {
|
if obj.Name == "" {
|
||||||
return fmt.Errorf("include name is empty")
|
return fmt.Errorf("include name is empty")
|
||||||
}
|
}
|
||||||
@@ -4800,6 +4910,8 @@ func (obj *StmtInclude) Interpolate() (interfaces.Stmt, error) {
|
|||||||
orig = obj.orig
|
orig = obj.orig
|
||||||
}
|
}
|
||||||
return &StmtInclude{
|
return &StmtInclude{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
//class: obj.class, // TODO: is this necessary?
|
//class: obj.class, // TODO: is this necessary?
|
||||||
orig: orig,
|
orig: orig,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
@@ -4834,6 +4946,8 @@ func (obj *StmtInclude) Copy() (interfaces.Stmt, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &StmtInclude{
|
return &StmtInclude{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
//class: obj.class, // TODO: is this necessary?
|
//class: obj.class, // TODO: is this necessary?
|
||||||
orig: orig,
|
orig: orig,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
@@ -5051,6 +5165,7 @@ func (obj *StmtInclude) TypeCheck() ([]*interfaces.UnificationInvariant, error)
|
|||||||
// add invariants between the args and the class
|
// add invariants between the args and the class
|
||||||
if typExpr := obj.class.Args[i].Type; typExpr != nil {
|
if typExpr := obj.class.Args[i].Type; typExpr != nil {
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: x,
|
Expr: x,
|
||||||
Expect: typExpr, // type of arg
|
Expect: typExpr, // type of arg
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -5100,6 +5215,9 @@ func (obj *StmtInclude) Output(table map[interfaces.Func]types.Value) (*interfac
|
|||||||
// file. As with any statement, it produces output, but that output is empty. To
|
// file. As with any statement, it produces output, but that output is empty. To
|
||||||
// benefit from its inclusion, reference the scope definitions you want.
|
// benefit from its inclusion, reference the scope definitions you want.
|
||||||
type StmtImport struct {
|
type StmtImport struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
Alias string
|
Alias string
|
||||||
}
|
}
|
||||||
@@ -5118,7 +5236,9 @@ func (obj *StmtImport) Apply(fn func(interfaces.Node) error) error { return fn(o
|
|||||||
|
|
||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtImport) Init(*interfaces.Data) error {
|
func (obj *StmtImport) Init(data *interfaces.Data) error {
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Name == "" {
|
if obj.Name == "" {
|
||||||
return fmt.Errorf("import name is empty")
|
return fmt.Errorf("import name is empty")
|
||||||
}
|
}
|
||||||
@@ -5130,6 +5250,8 @@ func (obj *StmtImport) Init(*interfaces.Data) error {
|
|||||||
// on any child elements and builds the new node with those new node contents.
|
// on any child elements and builds the new node with those new node contents.
|
||||||
func (obj *StmtImport) Interpolate() (interfaces.Stmt, error) {
|
func (obj *StmtImport) Interpolate() (interfaces.Stmt, error) {
|
||||||
return &StmtImport{
|
return &StmtImport{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
Alias: obj.Alias,
|
Alias: obj.Alias,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -5202,6 +5324,8 @@ func (obj *StmtImport) Output(map[interfaces.Func]types.Value) (*interfaces.Outp
|
|||||||
// formatting) but so that they can exist anywhere in the code. Currently these
|
// formatting) but so that they can exist anywhere in the code. Currently these
|
||||||
// are dropped by the lexer.
|
// are dropped by the lexer.
|
||||||
type StmtComment struct {
|
type StmtComment struct {
|
||||||
|
Textarea
|
||||||
|
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5219,7 +5343,9 @@ func (obj *StmtComment) Apply(fn func(interfaces.Node) error) error { return fn(
|
|||||||
|
|
||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *StmtComment) Init(*interfaces.Data) error {
|
func (obj *StmtComment) Init(data *interfaces.Data) error {
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5280,6 +5406,8 @@ func (obj *StmtComment) Output(map[interfaces.Func]types.Value) (*interfaces.Out
|
|||||||
|
|
||||||
// ExprBool is a representation of a boolean.
|
// ExprBool is a representation of a boolean.
|
||||||
type ExprBool struct {
|
type ExprBool struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
|
|
||||||
V bool
|
V bool
|
||||||
@@ -5297,7 +5425,11 @@ func (obj *ExprBool) Apply(fn func(interfaces.Node) error) error { return fn(obj
|
|||||||
|
|
||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprBool) Init(*interfaces.Data) error { return nil }
|
func (obj *ExprBool) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Interpolate returns a new node (aka a copy) once it has been expanded. This
|
// Interpolate returns a new node (aka a copy) once it has been expanded. This
|
||||||
// generally increases the size of the AST when it is used. It calls Interpolate
|
// generally increases the size of the AST when it is used. It calls Interpolate
|
||||||
@@ -5305,6 +5437,8 @@ func (obj *ExprBool) Init(*interfaces.Data) error { return nil }
|
|||||||
// Here it simply returns itself, as no interpolation is possible.
|
// Here it simply returns itself, as no interpolation is possible.
|
||||||
func (obj *ExprBool) Interpolate() (interfaces.Expr, error) {
|
func (obj *ExprBool) Interpolate() (interfaces.Expr, error) {
|
||||||
return &ExprBool{
|
return &ExprBool{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
V: obj.V,
|
V: obj.V,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -5359,6 +5493,7 @@ func (obj *ExprBool) Infer() (*types.Type, []*interfaces.UnificationInvariant, e
|
|||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
return types.TypeBool, []*interfaces.UnificationInvariant{
|
return types.TypeBool, []*interfaces.UnificationInvariant{
|
||||||
{
|
{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: types.TypeBool,
|
Expect: types.TypeBool,
|
||||||
Actual: types.TypeBool,
|
Actual: types.TypeBool,
|
||||||
@@ -5424,6 +5559,7 @@ func (obj *ExprBool) Value() (types.Value, error) {
|
|||||||
|
|
||||||
// ExprStr is a representation of a string.
|
// ExprStr is a representation of a string.
|
||||||
type ExprStr struct {
|
type ExprStr struct {
|
||||||
|
Textarea
|
||||||
data *interfaces.Data
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
|
|
||||||
@@ -5444,6 +5580,7 @@ func (obj *ExprStr) Apply(fn func(interfaces.Node) error) error { return fn(obj)
|
|||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprStr) Init(data *interfaces.Data) error {
|
func (obj *ExprStr) Init(data *interfaces.Data) error {
|
||||||
obj.data = data
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5455,6 +5592,7 @@ func (obj *ExprStr) Init(data *interfaces.Data) error {
|
|||||||
// a function which returns a string as its root. Otherwise it returns itself.
|
// a function which returns a string as its root. Otherwise it returns itself.
|
||||||
func (obj *ExprStr) Interpolate() (interfaces.Expr, error) {
|
func (obj *ExprStr) Interpolate() (interfaces.Expr, error) {
|
||||||
pos := &interfaces.Pos{
|
pos := &interfaces.Pos{
|
||||||
|
// XXX: populate this?
|
||||||
// column/line number, starting at 1
|
// column/line number, starting at 1
|
||||||
//Column: -1, // TODO
|
//Column: -1, // TODO
|
||||||
//Line: -1, // TODO
|
//Line: -1, // TODO
|
||||||
@@ -5474,6 +5612,7 @@ func (obj *ExprStr) Interpolate() (interfaces.Expr, error) {
|
|||||||
LexParser: obj.data.LexParser,
|
LexParser: obj.data.LexParser,
|
||||||
Downloader: obj.data.Downloader,
|
Downloader: obj.data.Downloader,
|
||||||
StrInterpolater: obj.data.StrInterpolater,
|
StrInterpolater: obj.data.StrInterpolater,
|
||||||
|
SourceFinder: obj.data.SourceFinder,
|
||||||
//World: obj.data.World, // TODO: do we need this?
|
//World: obj.data.World, // TODO: do we need this?
|
||||||
|
|
||||||
Prefix: obj.data.Prefix,
|
Prefix: obj.data.Prefix,
|
||||||
@@ -5489,6 +5628,7 @@ func (obj *ExprStr) Interpolate() (interfaces.Expr, error) {
|
|||||||
}
|
}
|
||||||
if result == nil {
|
if result == nil {
|
||||||
return &ExprStr{
|
return &ExprStr{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
V: obj.V,
|
V: obj.V,
|
||||||
@@ -5556,6 +5696,7 @@ func (obj *ExprStr) Infer() (*types.Type, []*interfaces.UnificationInvariant, er
|
|||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
return types.TypeStr, []*interfaces.UnificationInvariant{
|
return types.TypeStr, []*interfaces.UnificationInvariant{
|
||||||
{
|
{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: types.TypeStr,
|
Expect: types.TypeStr,
|
||||||
Actual: types.TypeStr,
|
Actual: types.TypeStr,
|
||||||
@@ -5620,6 +5761,8 @@ func (obj *ExprStr) Value() (types.Value, error) {
|
|||||||
|
|
||||||
// ExprInt is a representation of an int.
|
// ExprInt is a representation of an int.
|
||||||
type ExprInt struct {
|
type ExprInt struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
|
|
||||||
V int64
|
V int64
|
||||||
@@ -5637,7 +5780,11 @@ func (obj *ExprInt) Apply(fn func(interfaces.Node) error) error { return fn(obj)
|
|||||||
|
|
||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprInt) Init(*interfaces.Data) error { return nil }
|
func (obj *ExprInt) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Interpolate returns a new node (aka a copy) once it has been expanded. This
|
// Interpolate returns a new node (aka a copy) once it has been expanded. This
|
||||||
// generally increases the size of the AST when it is used. It calls Interpolate
|
// generally increases the size of the AST when it is used. It calls Interpolate
|
||||||
@@ -5645,6 +5792,8 @@ func (obj *ExprInt) Init(*interfaces.Data) error { return nil }
|
|||||||
// Here it simply returns itself, as no interpolation is possible.
|
// Here it simply returns itself, as no interpolation is possible.
|
||||||
func (obj *ExprInt) Interpolate() (interfaces.Expr, error) {
|
func (obj *ExprInt) Interpolate() (interfaces.Expr, error) {
|
||||||
return &ExprInt{
|
return &ExprInt{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
V: obj.V,
|
V: obj.V,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -5699,6 +5848,7 @@ func (obj *ExprInt) Infer() (*types.Type, []*interfaces.UnificationInvariant, er
|
|||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
return types.TypeInt, []*interfaces.UnificationInvariant{
|
return types.TypeInt, []*interfaces.UnificationInvariant{
|
||||||
{
|
{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: types.TypeInt,
|
Expect: types.TypeInt,
|
||||||
Actual: types.TypeInt,
|
Actual: types.TypeInt,
|
||||||
@@ -5763,6 +5913,8 @@ func (obj *ExprInt) Value() (types.Value, error) {
|
|||||||
|
|
||||||
// ExprFloat is a representation of a float.
|
// ExprFloat is a representation of a float.
|
||||||
type ExprFloat struct {
|
type ExprFloat struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
|
|
||||||
V float64
|
V float64
|
||||||
@@ -5782,7 +5934,11 @@ func (obj *ExprFloat) Apply(fn func(interfaces.Node) error) error { return fn(ob
|
|||||||
|
|
||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprFloat) Init(*interfaces.Data) error { return nil }
|
func (obj *ExprFloat) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Interpolate returns a new node (aka a copy) once it has been expanded. This
|
// Interpolate returns a new node (aka a copy) once it has been expanded. This
|
||||||
// generally increases the size of the AST when it is used. It calls Interpolate
|
// generally increases the size of the AST when it is used. It calls Interpolate
|
||||||
@@ -5790,6 +5946,8 @@ func (obj *ExprFloat) Init(*interfaces.Data) error { return nil }
|
|||||||
// Here it simply returns itself, as no interpolation is possible.
|
// Here it simply returns itself, as no interpolation is possible.
|
||||||
func (obj *ExprFloat) Interpolate() (interfaces.Expr, error) {
|
func (obj *ExprFloat) Interpolate() (interfaces.Expr, error) {
|
||||||
return &ExprFloat{
|
return &ExprFloat{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
V: obj.V,
|
V: obj.V,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -5844,6 +6002,7 @@ func (obj *ExprFloat) Infer() (*types.Type, []*interfaces.UnificationInvariant,
|
|||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
return types.TypeFloat, []*interfaces.UnificationInvariant{
|
return types.TypeFloat, []*interfaces.UnificationInvariant{
|
||||||
{
|
{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: types.TypeFloat,
|
Expect: types.TypeFloat,
|
||||||
Actual: types.TypeFloat,
|
Actual: types.TypeFloat,
|
||||||
@@ -5908,6 +6067,8 @@ func (obj *ExprFloat) Value() (types.Value, error) {
|
|||||||
|
|
||||||
// ExprList is a representation of a list.
|
// ExprList is a representation of a list.
|
||||||
type ExprList struct {
|
type ExprList struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
|
|
||||||
@@ -5941,6 +6102,9 @@ func (obj *ExprList) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprList) Init(data *interfaces.Data) error {
|
func (obj *ExprList) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
for _, x := range obj.Elements {
|
for _, x := range obj.Elements {
|
||||||
if err := x.Init(data); err != nil {
|
if err := x.Init(data); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -5962,6 +6126,8 @@ func (obj *ExprList) Interpolate() (interfaces.Expr, error) {
|
|||||||
elements = append(elements, interpolated)
|
elements = append(elements, interpolated)
|
||||||
}
|
}
|
||||||
return &ExprList{
|
return &ExprList{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
Elements: elements,
|
Elements: elements,
|
||||||
@@ -5987,6 +6153,8 @@ func (obj *ExprList) Copy() (interfaces.Expr, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &ExprList{
|
return &ExprList{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
Elements: elements,
|
Elements: elements,
|
||||||
@@ -6136,6 +6304,7 @@ func (obj *ExprList) Infer() (*types.Type, []*interfaces.UnificationInvariant, e
|
|||||||
}
|
}
|
||||||
// This must be added even if redundant, so that we collect the obj ptr.
|
// This must be added even if redundant, so that we collect the obj ptr.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typExpr, // This is the type that we return.
|
Expect: typExpr, // This is the type that we return.
|
||||||
Actual: typType,
|
Actual: typType,
|
||||||
@@ -6262,6 +6431,8 @@ func (obj *ExprList) Value() (types.Value, error) {
|
|||||||
|
|
||||||
// ExprMap is a representation of a (dictionary) map.
|
// ExprMap is a representation of a (dictionary) map.
|
||||||
type ExprMap struct {
|
type ExprMap struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
|
|
||||||
@@ -6297,6 +6468,9 @@ func (obj *ExprMap) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprMap) Init(data *interfaces.Data) error {
|
func (obj *ExprMap) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
// XXX: Can we check that there aren't any duplicate keys? Can we Cmp?
|
// XXX: Can we check that there aren't any duplicate keys? Can we Cmp?
|
||||||
for _, x := range obj.KVs {
|
for _, x := range obj.KVs {
|
||||||
if err := x.Key.Init(data); err != nil {
|
if err := x.Key.Init(data); err != nil {
|
||||||
@@ -6330,6 +6504,8 @@ func (obj *ExprMap) Interpolate() (interfaces.Expr, error) {
|
|||||||
kvs = append(kvs, kv)
|
kvs = append(kvs, kv)
|
||||||
}
|
}
|
||||||
return &ExprMap{
|
return &ExprMap{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
KVs: kvs,
|
KVs: kvs,
|
||||||
@@ -6373,6 +6549,8 @@ func (obj *ExprMap) Copy() (interfaces.Expr, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &ExprMap{
|
return &ExprMap{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
KVs: kvs,
|
KVs: kvs,
|
||||||
@@ -6577,6 +6755,7 @@ func (obj *ExprMap) Infer() (*types.Type, []*interfaces.UnificationInvariant, er
|
|||||||
}
|
}
|
||||||
// This must be added even if redundant, so that we collect the obj ptr.
|
// This must be added even if redundant, so that we collect the obj ptr.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typExpr, // This is the type that we return.
|
Expect: typExpr, // This is the type that we return.
|
||||||
Actual: typType,
|
Actual: typType,
|
||||||
@@ -6741,12 +6920,16 @@ func (obj *ExprMap) Value() (types.Value, error) {
|
|||||||
// ExprMapKV represents a key and value pair in a (dictionary) map. This does
|
// ExprMapKV represents a key and value pair in a (dictionary) map. This does
|
||||||
// not satisfy the Expr interface.
|
// not satisfy the Expr interface.
|
||||||
type ExprMapKV struct {
|
type ExprMapKV struct {
|
||||||
|
Textarea
|
||||||
|
|
||||||
Key interfaces.Expr // keys can be strings, int's, etc...
|
Key interfaces.Expr // keys can be strings, int's, etc...
|
||||||
Val interfaces.Expr
|
Val interfaces.Expr
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExprStruct is a representation of a struct.
|
// ExprStruct is a representation of a struct.
|
||||||
type ExprStruct struct {
|
type ExprStruct struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
|
|
||||||
@@ -6779,6 +6962,9 @@ func (obj *ExprStruct) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprStruct) Init(data *interfaces.Data) error {
|
func (obj *ExprStruct) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
fields := make(map[string]struct{})
|
fields := make(map[string]struct{})
|
||||||
for _, x := range obj.Fields {
|
for _, x := range obj.Fields {
|
||||||
// Validate field names and ensure no duplicates!
|
// Validate field names and ensure no duplicates!
|
||||||
@@ -6811,6 +6997,8 @@ func (obj *ExprStruct) Interpolate() (interfaces.Expr, error) {
|
|||||||
fields = append(fields, field)
|
fields = append(fields, field)
|
||||||
}
|
}
|
||||||
return &ExprStruct{
|
return &ExprStruct{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
@@ -6842,6 +7030,8 @@ func (obj *ExprStruct) Copy() (interfaces.Expr, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &ExprStruct{
|
return &ExprStruct{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
Fields: fields,
|
Fields: fields,
|
||||||
@@ -7001,6 +7191,7 @@ func (obj *ExprStruct) Infer() (*types.Type, []*interfaces.UnificationInvariant,
|
|||||||
}
|
}
|
||||||
// This must be added even if redundant, so that we collect the obj ptr.
|
// This must be added even if redundant, so that we collect the obj ptr.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typExpr, // This is the type that we return.
|
Expect: typExpr, // This is the type that we return.
|
||||||
Actual: typType,
|
Actual: typType,
|
||||||
@@ -7133,6 +7324,8 @@ func (obj *ExprStruct) Value() (types.Value, error) {
|
|||||||
// ExprStructField represents a name value pair in a struct field. This does not
|
// ExprStructField represents a name value pair in a struct field. This does not
|
||||||
// satisfy the Expr interface.
|
// satisfy the Expr interface.
|
||||||
type ExprStructField struct {
|
type ExprStructField struct {
|
||||||
|
Textarea
|
||||||
|
|
||||||
Name string
|
Name string
|
||||||
Value interfaces.Expr
|
Value interfaces.Expr
|
||||||
}
|
}
|
||||||
@@ -7147,6 +7340,7 @@ type ExprStructField struct {
|
|||||||
// 4. A pure built-in function (set Values to a singleton)
|
// 4. A pure built-in function (set Values to a singleton)
|
||||||
// 5. A pure polymorphic built-in function (set Values to a list)
|
// 5. A pure polymorphic built-in function (set Values to a list)
|
||||||
type ExprFunc struct {
|
type ExprFunc struct {
|
||||||
|
Textarea
|
||||||
data *interfaces.Data
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
@@ -7310,6 +7504,7 @@ func (obj *ExprFunc) Interpolate() (interfaces.Expr, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &ExprFunc{
|
return &ExprFunc{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
@@ -7405,6 +7600,7 @@ func (obj *ExprFunc) Copy() (interfaces.Expr, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &ExprFunc{
|
return &ExprFunc{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope, // TODO: copy?
|
scope: obj.scope, // TODO: copy?
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
@@ -7749,6 +7945,7 @@ func (obj *ExprFunc) Infer() (*types.Type, []*interfaces.UnificationInvariant, e
|
|||||||
}
|
}
|
||||||
// This must be added even if redundant, so that we collect the obj ptr.
|
// This must be added even if redundant, so that we collect the obj ptr.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typExpr, // This is the type that we return.
|
Expect: typExpr, // This is the type that we return.
|
||||||
Actual: typType,
|
Actual: typType,
|
||||||
@@ -7912,6 +8109,7 @@ func (obj *ExprFunc) Value() (types.Value, error) {
|
|||||||
// declaration or implementation of a new function value. This struct has an
|
// declaration or implementation of a new function value. This struct has an
|
||||||
// analogous symmetry with ExprVar.
|
// analogous symmetry with ExprVar.
|
||||||
type ExprCall struct {
|
type ExprCall struct {
|
||||||
|
Textarea
|
||||||
data *interfaces.Data
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
@@ -7971,6 +8169,7 @@ func (obj *ExprCall) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprCall) Init(data *interfaces.Data) error {
|
func (obj *ExprCall) Init(data *interfaces.Data) error {
|
||||||
obj.data = data
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if obj.Name == "" && obj.Anon == nil {
|
if obj.Name == "" && obj.Anon == nil {
|
||||||
return fmt.Errorf("missing call name")
|
return fmt.Errorf("missing call name")
|
||||||
@@ -8016,6 +8215,7 @@ func (obj *ExprCall) Interpolate() (interfaces.Expr, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &ExprCall{
|
return &ExprCall{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
@@ -8088,6 +8288,7 @@ func (obj *ExprCall) Copy() (interfaces.Expr, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &ExprCall{
|
return &ExprCall{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
@@ -8537,6 +8738,7 @@ func (obj *ExprCall) Infer() (*types.Type, []*interfaces.UnificationInvariant, e
|
|||||||
}
|
}
|
||||||
// This must be added even if redundant, so that we collect the obj ptr.
|
// This must be added even if redundant, so that we collect the obj ptr.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typExpr, // This is the type that we return.
|
Expect: typExpr, // This is the type that we return.
|
||||||
Actual: typType,
|
Actual: typType,
|
||||||
@@ -8607,6 +8809,7 @@ func (obj *ExprCall) Infer() (*types.Type, []*interfaces.UnificationInvariant, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj.expr, // this should NOT be obj
|
Expr: obj.expr, // this should NOT be obj
|
||||||
Expect: typFunc, // TODO: are these two reversed here?
|
Expect: typFunc, // TODO: are these two reversed here?
|
||||||
Actual: typFn,
|
Actual: typFn,
|
||||||
@@ -8743,6 +8946,7 @@ func (obj *ExprCall) Value() (types.Value, error) {
|
|||||||
// ExprVar is a representation of a variable lookup. It returns the expression
|
// ExprVar is a representation of a variable lookup. It returns the expression
|
||||||
// that that variable refers to.
|
// that that variable refers to.
|
||||||
type ExprVar struct {
|
type ExprVar struct {
|
||||||
|
Textarea
|
||||||
data *interfaces.Data
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
@@ -8775,6 +8979,7 @@ func (obj *ExprVar) Init(data *interfaces.Data) error {
|
|||||||
// support variable, variables or anything crazy like that.
|
// support variable, variables or anything crazy like that.
|
||||||
func (obj *ExprVar) Interpolate() (interfaces.Expr, error) {
|
func (obj *ExprVar) Interpolate() (interfaces.Expr, error) {
|
||||||
return &ExprVar{
|
return &ExprVar{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
@@ -8789,6 +8994,7 @@ func (obj *ExprVar) Interpolate() (interfaces.Expr, error) {
|
|||||||
// and they won't be able to have different values.
|
// and they won't be able to have different values.
|
||||||
func (obj *ExprVar) Copy() (interfaces.Expr, error) {
|
func (obj *ExprVar) Copy() (interfaces.Expr, error) {
|
||||||
return &ExprVar{
|
return &ExprVar{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
@@ -8926,6 +9132,7 @@ func (obj *ExprVar) Infer() (*types.Type, []*interfaces.UnificationInvariant, er
|
|||||||
|
|
||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typ,
|
Expect: typ,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -9153,6 +9360,7 @@ func (obj *ExprParam) Infer() (*types.Type, []*interfaces.UnificationInvariant,
|
|||||||
|
|
||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typ,
|
Expect: typ,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -9460,6 +9668,7 @@ func (obj *ExprTopLevel) Infer() (*types.Type, []*interfaces.UnificationInvarian
|
|||||||
|
|
||||||
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
// This adds the obj ptr, so it's seen as an expr that we need to solve.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typ,
|
Expect: typ,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -9654,6 +9863,7 @@ func (obj *ExprSingleton) Infer() (*types.Type, []*interfaces.UnificationInvaria
|
|||||||
// This adds the obj ptr, so it's seen as an expr that we need
|
// This adds the obj ptr, so it's seen as an expr that we need
|
||||||
// to solve.
|
// to solve.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typ,
|
Expect: typ,
|
||||||
Actual: typ,
|
Actual: typ,
|
||||||
@@ -9717,6 +9927,8 @@ func (obj *ExprSingleton) Value() (types.Value, error) {
|
|||||||
// returns a value. As a result, it has a type. This is different from a StmtIf,
|
// returns a value. As a result, it has a type. This is different from a StmtIf,
|
||||||
// which does not need to have both branches, and which does not return a value.
|
// which does not need to have both branches, and which does not return a value.
|
||||||
type ExprIf struct {
|
type ExprIf struct {
|
||||||
|
Textarea
|
||||||
|
data *interfaces.Data
|
||||||
scope *interfaces.Scope // store for referencing this later
|
scope *interfaces.Scope // store for referencing this later
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
|
|
||||||
@@ -9754,6 +9966,9 @@ func (obj *ExprIf) Apply(fn func(interfaces.Node) error) error {
|
|||||||
// Init initializes this branch of the AST, and returns an error if it fails to
|
// Init initializes this branch of the AST, and returns an error if it fails to
|
||||||
// validate.
|
// validate.
|
||||||
func (obj *ExprIf) Init(data *interfaces.Data) error {
|
func (obj *ExprIf) Init(data *interfaces.Data) error {
|
||||||
|
obj.data = data
|
||||||
|
obj.Textarea.Setup(data)
|
||||||
|
|
||||||
if err := obj.Condition.Init(data); err != nil {
|
if err := obj.Condition.Init(data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -9785,6 +10000,8 @@ func (obj *ExprIf) Interpolate() (interfaces.Expr, error) {
|
|||||||
return nil, errwrap.Wrapf(err, "could not interpolate ElseBranch")
|
return nil, errwrap.Wrapf(err, "could not interpolate ElseBranch")
|
||||||
}
|
}
|
||||||
return &ExprIf{
|
return &ExprIf{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -9823,6 +10040,8 @@ func (obj *ExprIf) Copy() (interfaces.Expr, error) {
|
|||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
return &ExprIf{
|
return &ExprIf{
|
||||||
|
Textarea: obj.Textarea,
|
||||||
|
data: obj.data,
|
||||||
scope: obj.scope,
|
scope: obj.scope,
|
||||||
typ: obj.typ,
|
typ: obj.typ,
|
||||||
Condition: condition,
|
Condition: condition,
|
||||||
@@ -10021,6 +10240,7 @@ func (obj *ExprIf) Infer() (*types.Type, []*interfaces.UnificationInvariant, err
|
|||||||
}
|
}
|
||||||
// This must be added even if redundant, so that we collect the obj ptr.
|
// This must be added even if redundant, so that we collect the obj ptr.
|
||||||
invar := &interfaces.UnificationInvariant{
|
invar := &interfaces.UnificationInvariant{
|
||||||
|
Node: obj,
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
Expect: typExpr, // This is the type that we return.
|
Expect: typExpr, // This is the type that we return.
|
||||||
Actual: typType,
|
Actual: typType,
|
||||||
|
|||||||
155
lang/ast/util.go
155
lang/ast/util.go
@@ -31,6 +31,7 @@ package ast
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -40,6 +41,7 @@ import (
|
|||||||
"github.com/purpleidea/mgmt/lang/funcs/vars"
|
"github.com/purpleidea/mgmt/lang/funcs/vars"
|
||||||
"github.com/purpleidea/mgmt/lang/interfaces"
|
"github.com/purpleidea/mgmt/lang/interfaces"
|
||||||
"github.com/purpleidea/mgmt/lang/types"
|
"github.com/purpleidea/mgmt/lang/types"
|
||||||
|
"github.com/purpleidea/mgmt/util"
|
||||||
"github.com/purpleidea/mgmt/util/errwrap"
|
"github.com/purpleidea/mgmt/util/errwrap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -393,3 +395,156 @@ func lambdaScopeFeedback(scope *interfaces.Scope, logf func(format string, v ...
|
|||||||
logf("$%s(...)", name)
|
logf("$%s(...)", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Textarea stores the coordinates of a statement or expression in the form of a
|
||||||
|
// starting line/column and ending line/column.
|
||||||
|
type Textarea struct {
|
||||||
|
// debug represents if we're running in debug mode or not.
|
||||||
|
debug bool
|
||||||
|
|
||||||
|
// logf is a logger which should be used.
|
||||||
|
logf func(format string, v ...interface{})
|
||||||
|
|
||||||
|
// sf is the SourceFinder function implementation that maps a filename
|
||||||
|
// to the source.
|
||||||
|
sf interfaces.SourceFinderFunc
|
||||||
|
|
||||||
|
// path is the full path/filename where this text area exists.
|
||||||
|
path string
|
||||||
|
|
||||||
|
// This data is zero-based. (Eg: first line of file is 0)
|
||||||
|
startLine int // first
|
||||||
|
startColumn int // left
|
||||||
|
endLine int // last
|
||||||
|
endColumn int // right
|
||||||
|
|
||||||
|
isSet bool
|
||||||
|
|
||||||
|
// Bug5819 works around issue https://github.com/golang/go/issues/5819
|
||||||
|
Bug5819 interface{} // XXX: workaround
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup is used during AST initialization in order to store in each AST node
|
||||||
|
// the name of the source file from which it was generated.
|
||||||
|
func (obj *Textarea) Setup(data *interfaces.Data) {
|
||||||
|
obj.debug = data.Debug
|
||||||
|
obj.logf = data.Logf
|
||||||
|
obj.sf = data.SourceFinder
|
||||||
|
obj.path = data.AbsFilename()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSet returns if the position was already set with Locate already.
|
||||||
|
func (obj *Textarea) IsSet() bool {
|
||||||
|
return obj.isSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate is used by the parser to store the token positions in AST nodes. The
|
||||||
|
// path will be filled during AST node initialization usually, because the
|
||||||
|
// parser does not know the name of the file it is processing.
|
||||||
|
func (obj *Textarea) Locate(line int, col int, endline int, endcol int) {
|
||||||
|
obj.startLine = line
|
||||||
|
obj.startColumn = col
|
||||||
|
obj.endLine = endline
|
||||||
|
obj.endColumn = endcol
|
||||||
|
obj.isSet = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pos returns the starting line/column of an AST node.
|
||||||
|
func (obj *Textarea) Pos() (int, int) {
|
||||||
|
return obj.startLine, obj.startColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
// End returns the end line/column of an AST node.
|
||||||
|
func (obj *Textarea) End() (int, int) {
|
||||||
|
return obj.endLine, obj.endColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path returns the name of the source file that holds the code for an AST node.
|
||||||
|
func (obj *Textarea) Path() string {
|
||||||
|
return obj.path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filename returns the printable filename that we'd like to display. It tries
|
||||||
|
// to return a relative version if possible.
|
||||||
|
func (obj *Textarea) Filename() string {
|
||||||
|
if obj.path == "" {
|
||||||
|
return "<unknown>" // TODO: should this be <stdin> ?
|
||||||
|
}
|
||||||
|
|
||||||
|
wd, _ := os.Getwd() // ignore error since "" would just pass through
|
||||||
|
wd += "/" // it's a dir
|
||||||
|
if s, err := util.RemoveBasePath(obj.path, wd); err == nil {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byline gives a succinct representation of the Textarea, but is useful only in
|
||||||
|
// debugging. In order to generate pretty error messages, see HighlightText.
|
||||||
|
func (obj *Textarea) Byline() string {
|
||||||
|
// We convert to 1-based for user display.
|
||||||
|
return fmt.Sprintf("%s @ %d:%d-%d:%d", obj.Filename(), obj.startLine+1, obj.startColumn+1, obj.endLine+1, obj.endColumn+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HighlightText generates a generic description that just visually indicates
|
||||||
|
// part of the line described by a Textarea. If the coordinates that are passed
|
||||||
|
// span multiple lines, don't show those lines, but just a description of the
|
||||||
|
// area. If it can't generate a valid snippet, then it returns the empty string.
|
||||||
|
func (obj *Textarea) HighlightText() string {
|
||||||
|
b, err := obj.sf(obj.path) // source finder!
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
contents := string(b)
|
||||||
|
|
||||||
|
result := &strings.Builder{}
|
||||||
|
|
||||||
|
result.WriteString(obj.Byline())
|
||||||
|
|
||||||
|
lines := strings.Split(contents, "\n")
|
||||||
|
if len(lines) < obj.endLine-1 {
|
||||||
|
// XXX: out of bounds?
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
result.WriteString("\n--\n")
|
||||||
|
|
||||||
|
if obj.startLine == obj.endLine {
|
||||||
|
line := lines[obj.startLine] + "\n"
|
||||||
|
text := strings.TrimLeft(line, " \t")
|
||||||
|
indent := strings.TrimSuffix(line, text)
|
||||||
|
offset := len(indent)
|
||||||
|
|
||||||
|
result.WriteString(line)
|
||||||
|
result.WriteString(indent)
|
||||||
|
result.WriteString(strings.Repeat(" ", obj.startColumn-offset))
|
||||||
|
// TODO: add on the width of the second element as well
|
||||||
|
result.WriteString(strings.Repeat("^", obj.endColumn-obj.startColumn+1))
|
||||||
|
result.WriteString("\n")
|
||||||
|
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
line := lines[obj.startLine] + "\n"
|
||||||
|
text := strings.TrimLeft(line, " \t")
|
||||||
|
indent := strings.TrimSuffix(line, text)
|
||||||
|
offset := len(indent)
|
||||||
|
|
||||||
|
result.WriteString(line)
|
||||||
|
result.WriteString(indent)
|
||||||
|
result.WriteString(strings.Repeat(" ", obj.startColumn-offset))
|
||||||
|
result.WriteString("^ from here ...\n")
|
||||||
|
|
||||||
|
line = lines[obj.endLine] + "\n"
|
||||||
|
text = strings.TrimLeft(line, " \t")
|
||||||
|
indent = strings.TrimSuffix(line, text)
|
||||||
|
offset = len(indent)
|
||||||
|
|
||||||
|
result.WriteString(line)
|
||||||
|
result.WriteString(indent)
|
||||||
|
result.WriteString(strings.Repeat(" ", obj.startColumn-offset))
|
||||||
|
result.WriteString("^ ... to here\n")
|
||||||
|
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ func (obj *GAPI) Cli(info *gapi.Info) (*gapi.Deploy, error) {
|
|||||||
LexParser: parser.LexParse,
|
LexParser: parser.LexParse,
|
||||||
Downloader: downloader,
|
Downloader: downloader,
|
||||||
StrInterpolater: interpolate.StrInterpolate,
|
StrInterpolater: interpolate.StrInterpolate,
|
||||||
|
SourceFinder: os.ReadFile,
|
||||||
//Local: obj.Local, // TODO: do we need this?
|
//Local: obj.Local, // TODO: do we need this?
|
||||||
//World: obj.World, // TODO: do we need this?
|
//World: obj.World, // TODO: do we need this?
|
||||||
|
|
||||||
|
|||||||
@@ -230,6 +230,15 @@ type Data struct {
|
|||||||
// cycles.
|
// cycles.
|
||||||
StrInterpolater func(string, *Pos, *Data) (Expr, error)
|
StrInterpolater func(string, *Pos, *Data) (Expr, error)
|
||||||
|
|
||||||
|
// SourceFinder is a function that returns the contents of a source file
|
||||||
|
// when requested by filename. This data is used to annotate error
|
||||||
|
// messages with some context from the source, and as a result is
|
||||||
|
// optional. This function is passed in this way so that the different
|
||||||
|
// consumers of this can use different methods to find the source. The
|
||||||
|
// three main users are: (1) normal GAPI CLI, before the bundle is
|
||||||
|
// created, (2) the main bundled execution, and (3) the tests.
|
||||||
|
SourceFinder SourceFinderFunc
|
||||||
|
|
||||||
//World engine.World // TODO: do we need this?
|
//World engine.World // TODO: do we need this?
|
||||||
|
|
||||||
// Prefix provides a unique path prefix that we can namespace in. It is
|
// Prefix provides a unique path prefix that we can namespace in. It is
|
||||||
@@ -244,6 +253,16 @@ type Data struct {
|
|||||||
Logf func(format string, v ...interface{})
|
Logf func(format string, v ...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AbsFilename returns the absolute filename path to the code this Data struct
|
||||||
|
// is running. This is used to pull out a filename for error messages.
|
||||||
|
func (obj *Data) AbsFilename() string {
|
||||||
|
// TODO: is this correct? Do we want to check if Metadata is nil?
|
||||||
|
if obj == nil || obj.Metadata == nil { // for tests
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return obj.Base + obj.Metadata.Main
|
||||||
|
}
|
||||||
|
|
||||||
// Scope represents a mapping between a variables identifier and the
|
// Scope represents a mapping between a variables identifier and the
|
||||||
// corresponding expression it is bound to. Local scopes in this language exist
|
// corresponding expression it is bound to. Local scopes in this language exist
|
||||||
// and are formed by nesting within if statements. Child scopes can shadow
|
// and are formed by nesting within if statements. Child scopes can shadow
|
||||||
@@ -424,3 +443,39 @@ func EmptyOutput() *Output {
|
|||||||
Edges: []*Edge{},
|
Edges: []*Edge{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PositionableNode is the interface implemented by AST nodes that store their
|
||||||
|
// code position. It is implemented by node types that embed Textarea.
|
||||||
|
type PositionableNode interface {
|
||||||
|
// IsSet returns if the position was already set with Locate already.
|
||||||
|
IsSet() bool
|
||||||
|
|
||||||
|
// Locate sets the position in zero-based (start line, start column, end
|
||||||
|
// line, end column) format.
|
||||||
|
Locate(int, int, int, int)
|
||||||
|
|
||||||
|
// Pos returns the zero-based start line and then start column position.
|
||||||
|
Pos() (int, int)
|
||||||
|
|
||||||
|
// End returns the zero-based end line and then end column position.
|
||||||
|
End() (int, int)
|
||||||
|
|
||||||
|
// String returns a friendly representation of the positions.
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextDisplayer is a graph node that is aware of its position in the source
|
||||||
|
// code, and can emit a textual representation of that part of the source.
|
||||||
|
type TextDisplayer interface {
|
||||||
|
// Byline returns a simple version of the error location.
|
||||||
|
Byline() string
|
||||||
|
|
||||||
|
// HighlightText returns a textual representation of this definition
|
||||||
|
// for this node in source.
|
||||||
|
HighlightText() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SourceFinderFunc is the function signature used to return the contents of a
|
||||||
|
// source file when requested by filename. This data is used to annotate error
|
||||||
|
// messages with some context from the source, and as a result is optional.
|
||||||
|
type SourceFinderFunc = func(string) ([]byte, error)
|
||||||
|
|||||||
@@ -39,8 +39,12 @@ import (
|
|||||||
// solution. Those two types are symmetrical in that it doesn't matter which is
|
// solution. Those two types are symmetrical in that it doesn't matter which is
|
||||||
// used where, it only affects how we print out error messages.
|
// used where, it only affects how we print out error messages.
|
||||||
type UnificationInvariant struct { // formerly the SamInvariant
|
type UnificationInvariant struct { // formerly the SamInvariant
|
||||||
// Expr is the expression we are determining the type for. This improves
|
// Node is the AST node holding the expression. This improves our error
|
||||||
// our error messages.
|
// messages.
|
||||||
|
Node Node
|
||||||
|
|
||||||
|
// Expr is the expression we are determining the type for. This is what
|
||||||
|
// we are unifying. This improves our error messages.
|
||||||
Expr Expr
|
Expr Expr
|
||||||
|
|
||||||
// Expect is one of the two types to unify.
|
// Expect is one of the two types to unify.
|
||||||
@@ -65,6 +69,7 @@ func GenericCheck(obj Expr, typ *types.Type) ([]*UnificationInvariant, error) {
|
|||||||
|
|
||||||
invar := &UnificationInvariant{
|
invar := &UnificationInvariant{
|
||||||
Expr: obj,
|
Expr: obj,
|
||||||
|
Node: obj,
|
||||||
Expect: typ, // sam says not backwards
|
Expect: typ, // sam says not backwards
|
||||||
Actual: actual,
|
Actual: actual,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ func HilInterpolate(str string, pos *interfaces.Pos, data *interfaces.Data) (int
|
|||||||
LexParser: data.LexParser,
|
LexParser: data.LexParser,
|
||||||
Downloader: data.Downloader,
|
Downloader: data.Downloader,
|
||||||
StrInterpolater: data.StrInterpolater,
|
StrInterpolater: data.StrInterpolater,
|
||||||
|
SourceFinder: data.SourceFinder,
|
||||||
//World: data.World, // TODO: do we need this?
|
//World: data.World, // TODO: do we need this?
|
||||||
|
|
||||||
Prefix: data.Prefix,
|
Prefix: data.Prefix,
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ package interpolate
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -228,6 +229,9 @@ func TestInterpolate0(t *testing.T) {
|
|||||||
data := &interfaces.Data{
|
data := &interfaces.Data{
|
||||||
// TODO: add missing fields here if/when needed
|
// TODO: add missing fields here if/when needed
|
||||||
StrInterpolater: StrInterpolate,
|
StrInterpolater: StrInterpolate,
|
||||||
|
SourceFinder: func(string) ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
},
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
@@ -271,7 +275,7 @@ func TestInterpolate0(t *testing.T) {
|
|||||||
StripPackageNames: true,
|
StripPackageNames: true,
|
||||||
HidePrivateFields: true,
|
HidePrivateFields: true,
|
||||||
HideZeroValues: true,
|
HideZeroValues: true,
|
||||||
//FieldExclusions: regexp.MustCompile(`^(data)$`),
|
FieldExclusions: regexp.MustCompile(`^(Textarea)$`),
|
||||||
//FieldFilter func(reflect.StructField, reflect.Value) bool
|
//FieldFilter func(reflect.StructField, reflect.Value) bool
|
||||||
//HomePackage string
|
//HomePackage string
|
||||||
//Separator string
|
//Separator string
|
||||||
@@ -480,6 +484,9 @@ func TestInterpolateBasicStmt(t *testing.T) {
|
|||||||
data := &interfaces.Data{
|
data := &interfaces.Data{
|
||||||
// TODO: add missing fields here if/when needed
|
// TODO: add missing fields here if/when needed
|
||||||
StrInterpolater: StrInterpolate,
|
StrInterpolater: StrInterpolate,
|
||||||
|
SourceFinder: func(string) ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
},
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
@@ -787,6 +794,9 @@ func TestInterpolateBasicExpr(t *testing.T) {
|
|||||||
data := &interfaces.Data{
|
data := &interfaces.Data{
|
||||||
// TODO: add missing fields here if/when needed
|
// TODO: add missing fields here if/when needed
|
||||||
StrInterpolater: StrInterpolate,
|
StrInterpolater: StrInterpolate,
|
||||||
|
SourceFinder: func(string) ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
},
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
|
|||||||
@@ -181,11 +181,19 @@ func TestAstFunc1(t *testing.T) {
|
|||||||
t.Logf("comment: %s\n", comment)
|
t.Logf("comment: %s\n", comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sources := map[string][]byte{}
|
||||||
|
sourceFinder := func(path string) ([]byte, error) {
|
||||||
|
if b, exists := sources[path]; exists {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
// copy files out into the test temp directory
|
// copy files out into the test temp directory
|
||||||
var testOutput []byte
|
var testOutput []byte
|
||||||
var testConfig []byte
|
var testConfig []byte
|
||||||
found := false
|
found := false
|
||||||
for _, file := range archive.Files {
|
for _, file := range archive.Files {
|
||||||
|
sources["/"+file.Name] = file.Data // store!
|
||||||
if file.Name == "OUTPUT" {
|
if file.Name == "OUTPUT" {
|
||||||
testOutput = file.Data
|
testOutput = file.Data
|
||||||
found = true
|
found = true
|
||||||
@@ -247,6 +255,7 @@ func TestAstFunc1(t *testing.T) {
|
|||||||
if strings.HasPrefix(expstr, magicError) {
|
if strings.HasPrefix(expstr, magicError) {
|
||||||
errStr = strings.TrimPrefix(expstr, magicError)
|
errStr = strings.TrimPrefix(expstr, magicError)
|
||||||
expstr = errStr
|
expstr = errStr
|
||||||
|
t.Logf("errStr has length %d", len(errStr))
|
||||||
|
|
||||||
if strings.HasPrefix(expstr, magicErrorLexParse) {
|
if strings.HasPrefix(expstr, magicErrorLexParse) {
|
||||||
errStr = strings.TrimPrefix(expstr, magicErrorLexParse)
|
errStr = strings.TrimPrefix(expstr, magicErrorLexParse)
|
||||||
@@ -398,6 +407,7 @@ func TestAstFunc1(t *testing.T) {
|
|||||||
|
|
||||||
LexParser: parser.LexParse,
|
LexParser: parser.LexParse,
|
||||||
StrInterpolater: interpolate.StrInterpolate,
|
StrInterpolater: interpolate.StrInterpolate,
|
||||||
|
SourceFinder: sourceFinder,
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
@@ -675,11 +685,19 @@ func TestAstFunc2(t *testing.T) {
|
|||||||
t.Logf("comment: %s\n", comment)
|
t.Logf("comment: %s\n", comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sources := map[string][]byte{}
|
||||||
|
sourceFinder := func(path string) ([]byte, error) {
|
||||||
|
if b, exists := sources[path]; exists {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
// copy files out into the test temp directory
|
// copy files out into the test temp directory
|
||||||
var testOutput []byte
|
var testOutput []byte
|
||||||
var testConfig []byte
|
var testConfig []byte
|
||||||
found := false
|
found := false
|
||||||
for _, file := range archive.Files {
|
for _, file := range archive.Files {
|
||||||
|
sources["/"+file.Name] = file.Data // store!
|
||||||
if file.Name == "OUTPUT" {
|
if file.Name == "OUTPUT" {
|
||||||
testOutput = file.Data
|
testOutput = file.Data
|
||||||
found = true
|
found = true
|
||||||
@@ -939,6 +957,7 @@ func TestAstFunc2(t *testing.T) {
|
|||||||
|
|
||||||
LexParser: parser.LexParse,
|
LexParser: parser.LexParse,
|
||||||
StrInterpolater: interpolate.StrInterpolate,
|
StrInterpolater: interpolate.StrInterpolate,
|
||||||
|
SourceFinder: sourceFinder,
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
@@ -1495,11 +1514,19 @@ func TestAstFunc3(t *testing.T) {
|
|||||||
t.Logf("comment: %s\n", comment)
|
t.Logf("comment: %s\n", comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sources := map[string][]byte{}
|
||||||
|
sourceFinder := func(path string) ([]byte, error) {
|
||||||
|
if b, exists := sources[path]; exists {
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
// copy files out into the test temp directory
|
// copy files out into the test temp directory
|
||||||
var testOutput []byte
|
var testOutput []byte
|
||||||
var testConfig []byte
|
var testConfig []byte
|
||||||
found := false
|
found := false
|
||||||
for _, file := range archive.Files {
|
for _, file := range archive.Files {
|
||||||
|
sources["/"+file.Name] = file.Data // store!
|
||||||
if file.Name == "OUTPUT" {
|
if file.Name == "OUTPUT" {
|
||||||
testOutput = file.Data
|
testOutput = file.Data
|
||||||
found = true
|
found = true
|
||||||
@@ -1759,6 +1786,7 @@ func TestAstFunc3(t *testing.T) {
|
|||||||
|
|
||||||
LexParser: parser.LexParse,
|
LexParser: parser.LexParse,
|
||||||
StrInterpolater: interpolate.StrInterpolate,
|
StrInterpolater: interpolate.StrInterpolate,
|
||||||
|
SourceFinder: sourceFinder,
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ class c1($a, $b []str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: str("hello"): type error: list != str
|
# err: errUnify: type error: list != str: /main.mcl @ 4:1-4:25
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ test ["x",] {
|
|||||||
float32 => $b,
|
float32 => $b,
|
||||||
}
|
}
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: topLevel(func() { <built-in:_operator> }): type error: int != float
|
# err: errUnify: type error: int != float: /main.mcl @ 10:6-10:22
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
test fmt.printf("%d%d", 42) {} # should not pass, missing second int
|
test fmt.printf("%d%d", 42) {} # should not pass, missing second int
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: call:fmt.printf(str("%d%d"), int(42)): type error: str != list
|
# err: errUnify: type error: str != list: /main.mcl @ 2:1-2:30
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ test "t1" {
|
|||||||
stringptr => 42, # int, not str
|
stringptr => 42, # int, not str
|
||||||
}
|
}
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: int(42): type error: str != int
|
# err: errUnify: type error: str != int: /main.mcl @ 2:2-2:17
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ test "test" {}
|
|||||||
Test["${name}"] -> Test["test"] # must fail
|
Test["${name}"] -> Test["test"] # must fail
|
||||||
|
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: var(name): type error: str != list
|
# err: errUnify: type error: str != list: /main.mcl @ 6:1-6:15
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ test "test" {}
|
|||||||
Test["test"] -> Test["${name}"] # must fail
|
Test["test"] -> Test["${name}"] # must fail
|
||||||
|
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: var(name): type error: str != list
|
# err: errUnify: type error: str != list: /main.mcl @ 6:17-6:31
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ $name = ["a", "bb", "ccc",]
|
|||||||
test "${name}" {} # must fail
|
test "${name}" {} # must fail
|
||||||
|
|
||||||
-- OUTPUT --
|
-- OUTPUT --
|
||||||
# err: errUnify: unify error with: var(name): type error: str != list
|
# err: errUnify: type error: str != list: /main.mcl @ 4:1-4:17
|
||||||
|
|||||||
@@ -189,6 +189,10 @@ func (obj *Lang) Init(ctx context.Context) error {
|
|||||||
LexParser: parser.LexParse,
|
LexParser: parser.LexParse,
|
||||||
Downloader: nil, // XXX: is this used here?
|
Downloader: nil, // XXX: is this used here?
|
||||||
StrInterpolater: interpolate.StrInterpolate,
|
StrInterpolater: interpolate.StrInterpolate,
|
||||||
|
SourceFinder: func(string) ([]byte, error) {
|
||||||
|
// We're running a bundle as part of a deploy.
|
||||||
|
return nil, fmt.Errorf("not implemented") // XXX: read from the fs?
|
||||||
|
},
|
||||||
//Local: obj.Local, // TODO: do we need this?
|
//Local: obj.Local, // TODO: do we need this?
|
||||||
//World: obj.World, // TODO: do we need this?
|
//World: obj.World, // TODO: do we need this?
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -45,8 +46,9 @@ import (
|
|||||||
langUtil "github.com/purpleidea/mgmt/lang/util"
|
langUtil "github.com/purpleidea/mgmt/lang/util"
|
||||||
"github.com/purpleidea/mgmt/util"
|
"github.com/purpleidea/mgmt/util"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
godiff "github.com/kylelemons/godebug/diff"
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
"github.com/sanity-io/litter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLexParse0(t *testing.T) {
|
func TestLexParse0(t *testing.T) {
|
||||||
@@ -2221,6 +2223,36 @@ func TestLexParse0(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// double check because DeepEqual is different since the func exists
|
// double check because DeepEqual is different since the func exists
|
||||||
|
|
||||||
|
lo := &litter.Options{
|
||||||
|
//Compact: false,
|
||||||
|
StripPackageNames: true,
|
||||||
|
HidePrivateFields: true,
|
||||||
|
HideZeroValues: true,
|
||||||
|
FieldExclusions: regexp.MustCompile(`^(Textarea)$`),
|
||||||
|
//FieldFilter func(reflect.StructField, reflect.Value) bool
|
||||||
|
//HomePackage string
|
||||||
|
//Separator string
|
||||||
|
DisablePointerReplacement: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// The litter package adds pointer comments everywhere,
|
||||||
|
// which make it not diff correctly. Clean them here!
|
||||||
|
pattern := regexp.MustCompile(`\ \/\/\ p[0-9]+$`) // the p0, p1 comments...
|
||||||
|
clean := func(s string) string {
|
||||||
|
lines := []string{}
|
||||||
|
for _, line := range strings.Split(s, "\n") {
|
||||||
|
s := pattern.ReplaceAllLiteralString(line, "")
|
||||||
|
lines = append(lines, s)
|
||||||
|
}
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
lo1 := clean(lo.Sdump(exp))
|
||||||
|
lo2 := clean(lo.Sdump(xast))
|
||||||
|
if lo1 == lo2 { // simple diff
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// more details, for tricky cases:
|
// more details, for tricky cases:
|
||||||
diffable := &pretty.Config{
|
diffable := &pretty.Config{
|
||||||
Diffable: true,
|
Diffable: true,
|
||||||
@@ -2228,18 +2260,22 @@ func TestLexParse0(t *testing.T) {
|
|||||||
//PrintStringers: false, // always false!
|
//PrintStringers: false, // always false!
|
||||||
//PrintTextMarshalers: false,
|
//PrintTextMarshalers: false,
|
||||||
SkipZeroFields: true,
|
SkipZeroFields: true,
|
||||||
|
//Formatter: map[reflect.Type]interface{}{
|
||||||
|
// reflect.TypeOf(ast.Textarea{}): func(x ast.Textarea) string {
|
||||||
|
// return ""
|
||||||
|
// },
|
||||||
|
//},
|
||||||
}
|
}
|
||||||
diff := diffable.Compare(exp, xast)
|
diff := diffable.Compare(exp, xast)
|
||||||
if diff == "" { // bonus
|
if diff == "" { // bonus
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
diff = godiff.Diff(lo1, lo2) // for printing
|
||||||
|
|
||||||
t.Errorf("test #%d: AST did not match expected", index)
|
t.Errorf("test #%d: AST did not match expected", index)
|
||||||
// TODO: consider making our own recursive print function
|
// TODO: consider making our own recursive print function
|
||||||
t.Logf("test #%d: actual: \n\n%s\n", index, spew.Sdump(xast))
|
t.Logf("test #%d: actual: \n\n%s\n", index, lo1)
|
||||||
t.Logf("test #%d: expected: \n\n%s", index, spew.Sdump(exp))
|
t.Logf("test #%d: expected: \n\n%s", index, lo2)
|
||||||
|
|
||||||
t.Logf("test #%d: actual: \n\n%s\n", index, diffable.Sprint(xast))
|
|
||||||
t.Logf("test #%d: expected: \n\n%s", index, diffable.Sprint(exp))
|
|
||||||
t.Logf("test #%d: diff:\n%s", index, diff)
|
t.Logf("test #%d: diff:\n%s", index, diff)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,54 +166,55 @@ prog:
|
|||||||
$$.stmt = &ast.StmtProg{
|
$$.stmt = &ast.StmtProg{
|
||||||
Body: stmts,
|
Body: stmts,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
stmt:
|
stmt:
|
||||||
COMMENT
|
COMMENT
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtComment{
|
$$.stmt = &ast.StmtComment{
|
||||||
Value: $1.str,
|
Value: $1.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
| bind
|
| bind
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = $1.stmt
|
$$.stmt = $1.stmt
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
| panic
|
| panic
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = $1.stmt
|
$$.stmt = $1.stmt
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
| resource
|
| resource
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = $1.stmt
|
$$.stmt = $1.stmt
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
| edge
|
| edge
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = $1.stmt
|
$$.stmt = $1.stmt
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
| IF expr OPEN_CURLY prog CLOSE_CURLY
|
| IF expr OPEN_CURLY prog CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtIf{
|
$$.stmt = &ast.StmtIf{
|
||||||
Condition: $2.expr,
|
Condition: $2.expr,
|
||||||
ThenBranch: $4.stmt,
|
ThenBranch: $4.stmt,
|
||||||
//ElseBranch: nil,
|
//ElseBranch: nil,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
| IF expr OPEN_CURLY prog CLOSE_CURLY ELSE OPEN_CURLY prog CLOSE_CURLY
|
| IF expr OPEN_CURLY prog CLOSE_CURLY ELSE OPEN_CURLY prog CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtIf{
|
$$.stmt = &ast.StmtIf{
|
||||||
Condition: $2.expr,
|
Condition: $2.expr,
|
||||||
ThenBranch: $4.stmt,
|
ThenBranch: $4.stmt,
|
||||||
ElseBranch: $8.stmt,
|
ElseBranch: $8.stmt,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// this is the named version, iow, a user-defined function (statement)
|
// this is the named version, iow, a user-defined function (statement)
|
||||||
// `func name() { <expr> }`
|
// `func name() { <expr> }`
|
||||||
@@ -221,7 +222,6 @@ stmt:
|
|||||||
// `func name(<arg>, <arg>) { <expr> }`
|
// `func name(<arg>, <arg>) { <expr> }`
|
||||||
| FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY
|
| FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtFunc{
|
$$.stmt = &ast.StmtFunc{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Func: &ast.ExprFunc{
|
Func: &ast.ExprFunc{
|
||||||
@@ -230,11 +230,11 @@ stmt:
|
|||||||
Body: $7.expr,
|
Body: $7.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `func name(...) <type> { <expr> }`
|
// `func name(...) <type> { <expr> }`
|
||||||
| FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN type OPEN_CURLY expr CLOSE_CURLY
|
| FUNC_IDENTIFIER IDENTIFIER OPEN_PAREN args CLOSE_PAREN type OPEN_CURLY expr CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
fn := &ast.ExprFunc{
|
fn := &ast.ExprFunc{
|
||||||
Args: $4.args,
|
Args: $4.args,
|
||||||
Return: $6.typ, // return type is known
|
Return: $6.typ, // return type is known
|
||||||
@@ -271,191 +271,192 @@ stmt:
|
|||||||
Func: fn,
|
Func: fn,
|
||||||
Type: typ, // sam says add the type here instead...
|
Type: typ, // sam says add the type here instead...
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `class name { <prog> }`
|
// `class name { <prog> }`
|
||||||
| CLASS_IDENTIFIER colon_identifier OPEN_CURLY prog CLOSE_CURLY
|
| CLASS_IDENTIFIER colon_identifier OPEN_CURLY prog CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtClass{
|
$$.stmt = &ast.StmtClass{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
Body: $4.stmt,
|
Body: $4.stmt,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `class name(<arg>) { <prog> }`
|
// `class name(<arg>) { <prog> }`
|
||||||
// `class name(<arg>, <arg>) { <prog> }`
|
// `class name(<arg>, <arg>) { <prog> }`
|
||||||
| CLASS_IDENTIFIER colon_identifier OPEN_PAREN args CLOSE_PAREN OPEN_CURLY prog CLOSE_CURLY
|
| CLASS_IDENTIFIER colon_identifier OPEN_PAREN args CLOSE_PAREN OPEN_CURLY prog CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtClass{
|
$$.stmt = &ast.StmtClass{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Args: $4.args,
|
Args: $4.args,
|
||||||
Body: $7.stmt,
|
Body: $7.stmt,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `include name`
|
// `include name`
|
||||||
| INCLUDE_IDENTIFIER dotted_identifier
|
| INCLUDE_IDENTIFIER dotted_identifier
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtInclude{
|
$$.stmt = &ast.StmtInclude{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `include name(...)`
|
// `include name(...)`
|
||||||
| INCLUDE_IDENTIFIER dotted_identifier OPEN_PAREN call_args CLOSE_PAREN
|
| INCLUDE_IDENTIFIER dotted_identifier OPEN_PAREN call_args CLOSE_PAREN
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtInclude{
|
$$.stmt = &ast.StmtInclude{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Args: $4.exprs,
|
Args: $4.exprs,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `include name as foo`
|
// `include name as foo`
|
||||||
// TODO: should we support: `include name as *`
|
// TODO: should we support: `include name as *`
|
||||||
| INCLUDE_IDENTIFIER dotted_identifier AS_IDENTIFIER IDENTIFIER
|
| INCLUDE_IDENTIFIER dotted_identifier AS_IDENTIFIER IDENTIFIER
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtInclude{
|
$$.stmt = &ast.StmtInclude{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Alias: $4.str,
|
Alias: $4.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `include name(...) as foo`
|
// `include name(...) as foo`
|
||||||
// TODO: should we support: `include name(...) as *`
|
// TODO: should we support: `include name(...) as *`
|
||||||
| INCLUDE_IDENTIFIER dotted_identifier OPEN_PAREN call_args CLOSE_PAREN AS_IDENTIFIER IDENTIFIER
|
| INCLUDE_IDENTIFIER dotted_identifier OPEN_PAREN call_args CLOSE_PAREN AS_IDENTIFIER IDENTIFIER
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtInclude{
|
$$.stmt = &ast.StmtInclude{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Args: $4.exprs,
|
Args: $4.exprs,
|
||||||
Alias: $7.str,
|
Alias: $7.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `import "name"`
|
// `import "name"`
|
||||||
| IMPORT_IDENTIFIER STRING
|
| IMPORT_IDENTIFIER STRING
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtImport{
|
$$.stmt = &ast.StmtImport{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
//Alias: "",
|
//Alias: "",
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `import "name" as alias`
|
// `import "name" as alias`
|
||||||
| IMPORT_IDENTIFIER STRING AS_IDENTIFIER IDENTIFIER
|
| IMPORT_IDENTIFIER STRING AS_IDENTIFIER IDENTIFIER
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtImport{
|
$$.stmt = &ast.StmtImport{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Alias: $4.str,
|
Alias: $4.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `import "name" as *`
|
// `import "name" as *`
|
||||||
| IMPORT_IDENTIFIER STRING AS_IDENTIFIER MULTIPLY
|
| IMPORT_IDENTIFIER STRING AS_IDENTIFIER MULTIPLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtImport{
|
$$.stmt = &ast.StmtImport{
|
||||||
Name: $2.str,
|
Name: $2.str,
|
||||||
Alias: $4.str,
|
Alias: $4.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// resource bind
|
// resource bind
|
||||||
| rbind
|
| rbind
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = $1.stmt
|
$$.stmt = $1.stmt
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
;
|
;
|
||||||
expr:
|
expr:
|
||||||
BOOL
|
BOOL
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprBool{
|
$$.expr = &ast.ExprBool{
|
||||||
V: $1.bool,
|
V: $1.bool,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| STRING
|
| STRING
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprStr{
|
$$.expr = &ast.ExprStr{
|
||||||
V: $1.str,
|
V: $1.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| INTEGER
|
| INTEGER
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprInt{
|
$$.expr = &ast.ExprInt{
|
||||||
V: $1.int,
|
V: $1.int,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| FLOAT
|
| FLOAT
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprFloat{
|
$$.expr = &ast.ExprFloat{
|
||||||
V: $1.float,
|
V: $1.float,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| list
|
| list
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// TODO: list could be squashed in here directly...
|
// TODO: list could be squashed in here directly...
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| map
|
| map
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// TODO: map could be squashed in here directly...
|
// TODO: map could be squashed in here directly...
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| struct
|
| struct
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// TODO: struct could be squashed in here directly...
|
// TODO: struct could be squashed in here directly...
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| call
|
| call
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// TODO: call could be squashed in here directly...
|
// TODO: call could be squashed in here directly...
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| var
|
| var
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// TODO: var could be squashed in here directly...
|
// TODO: var could be squashed in here directly...
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| func
|
| func
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// TODO: var could be squashed in here directly...
|
// TODO: var could be squashed in here directly...
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| IF expr OPEN_CURLY expr CLOSE_CURLY ELSE OPEN_CURLY expr CLOSE_CURLY
|
| IF expr OPEN_CURLY expr CLOSE_CURLY ELSE OPEN_CURLY expr CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprIf{
|
$$.expr = &ast.ExprIf{
|
||||||
Condition: $2.expr,
|
Condition: $2.expr,
|
||||||
ThenBranch: $4.expr,
|
ThenBranch: $4.expr,
|
||||||
ElseBranch: $8.expr,
|
ElseBranch: $8.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// parenthesis wrap an expression for precedence
|
// parenthesis wrap an expression for precedence
|
||||||
| OPEN_PAREN expr CLOSE_PAREN
|
| OPEN_PAREN expr CLOSE_PAREN
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = $2.expr
|
$$.expr = $2.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
list:
|
list:
|
||||||
// `[42, 0, -13]`
|
// `[42, 0, -13]`
|
||||||
OPEN_BRACK list_elements CLOSE_BRACK
|
OPEN_BRACK list_elements CLOSE_BRACK
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprList{
|
$$.expr = &ast.ExprList{
|
||||||
Elements: $2.exprs,
|
Elements: $2.exprs,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
list_elements:
|
list_elements:
|
||||||
@@ -473,18 +474,18 @@ list_elements:
|
|||||||
list_element:
|
list_element:
|
||||||
expr COMMA
|
expr COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = $1.expr
|
$$.expr = $1.expr
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
map:
|
map:
|
||||||
// `{"hello" => "there", "world" => "big",}`
|
// `{"hello" => "there", "world" => "big",}`
|
||||||
OPEN_CURLY map_kvs CLOSE_CURLY
|
OPEN_CURLY map_kvs CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprMap{
|
$$.expr = &ast.ExprMap{
|
||||||
KVs: $2.mapKVs,
|
KVs: $2.mapKVs,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
map_kvs:
|
map_kvs:
|
||||||
@@ -513,7 +514,6 @@ struct:
|
|||||||
// `struct{answer => 0, truth => false, hello => "world",}`
|
// `struct{answer => 0, truth => false, hello => "world",}`
|
||||||
STRUCT_IDENTIFIER OPEN_CURLY struct_fields CLOSE_CURLY
|
STRUCT_IDENTIFIER OPEN_CURLY struct_fields CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprStruct{
|
$$.expr = &ast.ExprStruct{
|
||||||
Fields: $3.structFields,
|
Fields: $3.structFields,
|
||||||
}
|
}
|
||||||
@@ -546,18 +546,17 @@ call:
|
|||||||
// iter.map(...)
|
// iter.map(...)
|
||||||
dotted_identifier OPEN_PAREN call_args CLOSE_PAREN
|
dotted_identifier OPEN_PAREN call_args CLOSE_PAREN
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: $1.str,
|
Name: $1.str,
|
||||||
Args: $3.exprs,
|
Args: $3.exprs,
|
||||||
//Var: false, // default
|
//Var: false, // default
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// calling a function that's stored in a variable (a lambda)
|
// calling a function that's stored in a variable (a lambda)
|
||||||
// `$foo(4, "hey")` # call function value
|
// `$foo(4, "hey")` # call function value
|
||||||
| dotted_var_identifier OPEN_PAREN call_args CLOSE_PAREN
|
| dotted_var_identifier OPEN_PAREN call_args CLOSE_PAREN
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: $1.str,
|
Name: $1.str,
|
||||||
Args: $3.exprs,
|
Args: $3.exprs,
|
||||||
@@ -565,20 +564,20 @@ call:
|
|||||||
// prefix to the Name, but I felt this was more elegant.
|
// prefix to the Name, but I felt this was more elegant.
|
||||||
Var: true, // lambda
|
Var: true, // lambda
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// calling an inline function
|
// calling an inline function
|
||||||
| func OPEN_PAREN call_args CLOSE_PAREN
|
| func OPEN_PAREN call_args CLOSE_PAREN
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: "", // anonymous!
|
Name: "", // anonymous!
|
||||||
Args: $3.exprs,
|
Args: $3.exprs,
|
||||||
Anon: $1.expr,
|
Anon: $1.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr PLUS expr
|
| expr PLUS expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -589,10 +588,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr MINUS expr
|
| expr MINUS expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -603,10 +602,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr MULTIPLY expr
|
| expr MULTIPLY expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -617,10 +616,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr DIVIDE expr
|
| expr DIVIDE expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -631,10 +630,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr EQ expr
|
| expr EQ expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -645,10 +644,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr NEQ expr
|
| expr NEQ expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -659,10 +658,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr LT expr
|
| expr LT expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -673,10 +672,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr GT expr
|
| expr GT expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -687,10 +686,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr LTE expr
|
| expr LTE expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -701,10 +700,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr GTE expr
|
| expr GTE expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -715,10 +714,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr AND expr
|
| expr AND expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -729,10 +728,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr OR expr
|
| expr OR expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -743,10 +742,10 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| NOT expr
|
| NOT expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: operators.OperatorFuncName,
|
Name: operators.OperatorFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -756,13 +755,13 @@ call:
|
|||||||
$2.expr,
|
$2.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// lookup an index in a list or a key in a map
|
// lookup an index in a list or a key in a map
|
||||||
// lookup($foo, $key)
|
// lookup($foo, $key)
|
||||||
// `$foo[$key]` // no default specifier
|
// `$foo[$key]` // no default specifier
|
||||||
| expr OPEN_BRACK expr CLOSE_BRACK
|
| expr OPEN_BRACK expr CLOSE_BRACK
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: funcs.LookupFuncName,
|
Name: funcs.LookupFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -771,13 +770,13 @@ call:
|
|||||||
//$6.expr, // the default
|
//$6.expr, // the default
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// lookup an index in a list or a key in a map with a default
|
// lookup an index in a list or a key in a map with a default
|
||||||
// lookup_default($foo, $key, $default)
|
// lookup_default($foo, $key, $default)
|
||||||
// `$foo[$key] || "default"`
|
// `$foo[$key] || "default"`
|
||||||
| expr OPEN_BRACK expr CLOSE_BRACK DEFAULT expr
|
| expr OPEN_BRACK expr CLOSE_BRACK DEFAULT expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: funcs.LookupDefaultFuncName,
|
Name: funcs.LookupDefaultFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -786,13 +785,13 @@ call:
|
|||||||
$6.expr, // the default
|
$6.expr, // the default
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// lookup a field in a struct
|
// lookup a field in a struct
|
||||||
// _struct_lookup($foo, "field")
|
// _struct_lookup($foo, "field")
|
||||||
// $foo->field
|
// $foo->field
|
||||||
| expr ARROW IDENTIFIER
|
| expr ARROW IDENTIFIER
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: funcs.StructLookupFuncName,
|
Name: funcs.StructLookupFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -803,13 +802,13 @@ call:
|
|||||||
//$5.expr, // the default
|
//$5.expr, // the default
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// lookup a field in a struct with a default
|
// lookup a field in a struct with a default
|
||||||
// _struct_lookup_optional($foo, "field", "default")
|
// _struct_lookup_optional($foo, "field", "default")
|
||||||
// $foo->field || "default"
|
// $foo->field || "default"
|
||||||
| expr ARROW IDENTIFIER DEFAULT expr
|
| expr ARROW IDENTIFIER DEFAULT expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: funcs.StructLookupOptionalFuncName,
|
Name: funcs.StructLookupOptionalFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -820,10 +819,10 @@ call:
|
|||||||
$5.expr, // the default
|
$5.expr, // the default
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
| expr IN expr
|
| expr IN expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprCall{
|
$$.expr = &ast.ExprCall{
|
||||||
Name: funcs.ContainsFuncName,
|
Name: funcs.ContainsFuncName,
|
||||||
Args: []interfaces.Expr{
|
Args: []interfaces.Expr{
|
||||||
@@ -831,6 +830,7 @@ call:
|
|||||||
$3.expr,
|
$3.expr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
// list order gets us the position of the arg, but named params would work too!
|
// list order gets us the position of the arg, but named params would work too!
|
||||||
@@ -856,10 +856,10 @@ call_args:
|
|||||||
var:
|
var:
|
||||||
dotted_var_identifier
|
dotted_var_identifier
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprVar{
|
$$.expr = &ast.ExprVar{
|
||||||
Name: $1.str,
|
Name: $1.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
func:
|
func:
|
||||||
@@ -869,17 +869,16 @@ func:
|
|||||||
// `func(<arg>, <arg>) { <expr> }`
|
// `func(<arg>, <arg>) { <expr> }`
|
||||||
FUNC_IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY
|
FUNC_IDENTIFIER OPEN_PAREN args CLOSE_PAREN OPEN_CURLY expr CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprFunc{
|
$$.expr = &ast.ExprFunc{
|
||||||
Args: $3.args,
|
Args: $3.args,
|
||||||
//Return: nil,
|
//Return: nil,
|
||||||
Body: $6.expr,
|
Body: $6.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
// `func(...) <type> { <expr> }`
|
// `func(...) <type> { <expr> }`
|
||||||
| FUNC_IDENTIFIER OPEN_PAREN args CLOSE_PAREN type OPEN_CURLY expr CLOSE_CURLY
|
| FUNC_IDENTIFIER OPEN_PAREN args CLOSE_PAREN type OPEN_CURLY expr CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.expr = &ast.ExprFunc{
|
$$.expr = &ast.ExprFunc{
|
||||||
Args: $3.args,
|
Args: $3.args,
|
||||||
Return: $5.typ, // return type is known
|
Return: $5.typ, // return type is known
|
||||||
@@ -909,6 +908,7 @@ func:
|
|||||||
yylex.Error(fmt.Sprintf("%s: %+v", ErrParseSetType, err))
|
yylex.Error(fmt.Sprintf("%s: %+v", ErrParseSetType, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
args:
|
args:
|
||||||
@@ -949,17 +949,16 @@ bind:
|
|||||||
// `$s = "hey"`
|
// `$s = "hey"`
|
||||||
var_identifier EQUALS expr
|
var_identifier EQUALS expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtBind{
|
$$.stmt = &ast.StmtBind{
|
||||||
Ident: $1.str,
|
Ident: $1.str,
|
||||||
Value: $3.expr,
|
Value: $3.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// `$x bool = true`
|
// `$x bool = true`
|
||||||
// `$x int = if true { 42 } else { 13 }`
|
// `$x int = if true { 42 } else { 13 }`
|
||||||
| var_identifier type EQUALS expr
|
| var_identifier type EQUALS expr
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
var expr interfaces.Expr = $4.expr
|
var expr interfaces.Expr = $4.expr
|
||||||
// XXX: We still need to do this for now it seems...
|
// XXX: We still need to do this for now it seems...
|
||||||
if err := expr.SetType($2.typ); err != nil {
|
if err := expr.SetType($2.typ); err != nil {
|
||||||
@@ -971,6 +970,7 @@ bind:
|
|||||||
Value: expr,
|
Value: expr,
|
||||||
Type: $2.typ, // sam says add the type here instead...
|
Type: $2.typ, // sam says add the type here instead...
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
panic:
|
panic:
|
||||||
@@ -981,7 +981,6 @@ panic:
|
|||||||
//}
|
//}
|
||||||
PANIC_IDENTIFIER OPEN_PAREN call_args CLOSE_PAREN
|
PANIC_IDENTIFIER OPEN_PAREN call_args CLOSE_PAREN
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
call := &ast.ExprCall{
|
call := &ast.ExprCall{
|
||||||
Name: $1.str, // the function name
|
Name: $1.str, // the function name
|
||||||
Args: $3.exprs,
|
Args: $3.exprs,
|
||||||
@@ -1000,6 +999,7 @@ panic:
|
|||||||
ThenBranch: res,
|
ThenBranch: res,
|
||||||
//ElseBranch: nil,
|
//ElseBranch: nil,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
/* TODO: do we want to include this?
|
/* TODO: do we want to include this?
|
||||||
@@ -1007,7 +1007,6 @@ panic:
|
|||||||
rbind:
|
rbind:
|
||||||
var_identifier EQUALS resource
|
var_identifier EQUALS resource
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
// XXX: this kind of bind is different than the others, because
|
// XXX: this kind of bind is different than the others, because
|
||||||
// it can only really be used for send->recv stuff, eg:
|
// it can only really be used for send->recv stuff, eg:
|
||||||
// foo.SomeString -> bar.SomeOtherString
|
// foo.SomeString -> bar.SomeOtherString
|
||||||
@@ -1015,6 +1014,7 @@ rbind:
|
|||||||
Ident: $1.str,
|
Ident: $1.str,
|
||||||
Value: $3.stmt,
|
Value: $3.stmt,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.expr)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
*/
|
*/
|
||||||
@@ -1022,12 +1022,12 @@ resource:
|
|||||||
// `file "/tmp/hello" { ... }` or `aws:ec2 "/tmp/hello" { ... }`
|
// `file "/tmp/hello" { ... }` or `aws:ec2 "/tmp/hello" { ... }`
|
||||||
colon_identifier expr OPEN_CURLY resource_body CLOSE_CURLY
|
colon_identifier expr OPEN_CURLY resource_body CLOSE_CURLY
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtRes{
|
$$.stmt = &ast.StmtRes{
|
||||||
Kind: $1.str,
|
Kind: $1.str,
|
||||||
Name: $2.expr,
|
Name: $2.expr,
|
||||||
Contents: $4.resContents,
|
Contents: $4.resContents,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
resource_body:
|
resource_body:
|
||||||
@@ -1080,53 +1080,52 @@ resource_body:
|
|||||||
resource_field:
|
resource_field:
|
||||||
IDENTIFIER ROCKET expr COMMA
|
IDENTIFIER ROCKET expr COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.resField = &ast.StmtResField{
|
$$.resField = &ast.StmtResField{
|
||||||
Field: $1.str,
|
Field: $1.str,
|
||||||
Value: $3.expr,
|
Value: $3.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resField)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
conditional_resource_field:
|
conditional_resource_field:
|
||||||
// content => $present ?: "hello",
|
// content => $present ?: "hello",
|
||||||
IDENTIFIER ROCKET expr ELVIS expr COMMA
|
IDENTIFIER ROCKET expr ELVIS expr COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.resField = &ast.StmtResField{
|
$$.resField = &ast.StmtResField{
|
||||||
Field: $1.str,
|
Field: $1.str,
|
||||||
Value: $5.expr,
|
Value: $5.expr,
|
||||||
Condition: $3.expr,
|
Condition: $3.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resField)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
resource_edge:
|
resource_edge:
|
||||||
// Before => Test["t1"],
|
// Before => Test["t1"],
|
||||||
CAPITALIZED_IDENTIFIER ROCKET edge_half COMMA
|
CAPITALIZED_IDENTIFIER ROCKET edge_half COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.resEdge = &ast.StmtResEdge{
|
$$.resEdge = &ast.StmtResEdge{
|
||||||
Property: $1.str,
|
Property: $1.str,
|
||||||
EdgeHalf: $3.edgeHalf,
|
EdgeHalf: $3.edgeHalf,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resEdge)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
conditional_resource_edge:
|
conditional_resource_edge:
|
||||||
// Before => $present ?: Test["t1"],
|
// Before => $present ?: Test["t1"],
|
||||||
CAPITALIZED_IDENTIFIER ROCKET expr ELVIS edge_half COMMA
|
CAPITALIZED_IDENTIFIER ROCKET expr ELVIS edge_half COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.resEdge = &ast.StmtResEdge{
|
$$.resEdge = &ast.StmtResEdge{
|
||||||
Property: $1.str,
|
Property: $1.str,
|
||||||
EdgeHalf: $5.edgeHalf,
|
EdgeHalf: $5.edgeHalf,
|
||||||
Condition: $3.expr,
|
Condition: $3.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resEdge)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
resource_meta:
|
resource_meta:
|
||||||
// Meta:noop => true,
|
// Meta:noop => true,
|
||||||
CAPITALIZED_IDENTIFIER COLON IDENTIFIER ROCKET expr COMMA
|
CAPITALIZED_IDENTIFIER COLON IDENTIFIER ROCKET expr COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
||||||
// this will ultimately cause a parser error to occur...
|
// this will ultimately cause a parser error to occur...
|
||||||
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
||||||
@@ -1135,6 +1134,7 @@ resource_meta:
|
|||||||
Property: $3.str,
|
Property: $3.str,
|
||||||
MetaExpr: $5.expr,
|
MetaExpr: $5.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
conditional_resource_meta:
|
conditional_resource_meta:
|
||||||
@@ -1151,13 +1151,13 @@ conditional_resource_meta:
|
|||||||
MetaExpr: $7.expr,
|
MetaExpr: $7.expr,
|
||||||
Condition: $5.expr,
|
Condition: $5.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
resource_meta_struct:
|
resource_meta_struct:
|
||||||
// Meta => struct{meta => true, retry => 3,},
|
// Meta => struct{meta => true, retry => 3,},
|
||||||
CAPITALIZED_IDENTIFIER ROCKET expr COMMA
|
CAPITALIZED_IDENTIFIER ROCKET expr COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
||||||
// this will ultimately cause a parser error to occur...
|
// this will ultimately cause a parser error to occur...
|
||||||
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
||||||
@@ -1166,13 +1166,13 @@ resource_meta_struct:
|
|||||||
Property: $1.str,
|
Property: $1.str,
|
||||||
MetaExpr: $3.expr,
|
MetaExpr: $3.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
conditional_resource_meta_struct:
|
conditional_resource_meta_struct:
|
||||||
// Meta => $present ?: struct{poll => 60, sema => ["foo:1", "bar:3",],},
|
// Meta => $present ?: struct{poll => 60, sema => ["foo:1", "bar:3",],},
|
||||||
CAPITALIZED_IDENTIFIER ROCKET expr ELVIS expr COMMA
|
CAPITALIZED_IDENTIFIER ROCKET expr ELVIS expr COMMA
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
if strings.ToLower($1.str) != strings.ToLower(ast.MetaField) {
|
||||||
// this will ultimately cause a parser error to occur...
|
// this will ultimately cause a parser error to occur...
|
||||||
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
yylex.Error(fmt.Sprintf("%s: %s", ErrParseResFieldInvalid, $1.str))
|
||||||
@@ -1182,6 +1182,7 @@ conditional_resource_meta_struct:
|
|||||||
MetaExpr: $5.expr,
|
MetaExpr: $5.expr,
|
||||||
Condition: $3.expr,
|
Condition: $3.expr,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.resMeta)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
edge:
|
edge:
|
||||||
@@ -1190,16 +1191,15 @@ edge:
|
|||||||
// Test["t1"] -> Test["t2"] -> Test["t3"] # chain or pair
|
// Test["t1"] -> Test["t2"] -> Test["t3"] # chain or pair
|
||||||
edge_half_list
|
edge_half_list
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtEdge{
|
$$.stmt = &ast.StmtEdge{
|
||||||
EdgeHalfList: $1.edgeHalfList,
|
EdgeHalfList: $1.edgeHalfList,
|
||||||
//Notify: false, // unused here
|
//Notify: false, // unused here
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
// Test["t1"].foo_send -> Test["t2"].blah_recv # send/recv
|
// Test["t1"].foo_send -> Test["t2"].blah_recv # send/recv
|
||||||
| edge_half_sendrecv ARROW edge_half_sendrecv
|
| edge_half_sendrecv ARROW edge_half_sendrecv
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.stmt = &ast.StmtEdge{
|
$$.stmt = &ast.StmtEdge{
|
||||||
EdgeHalfList: []*ast.StmtEdgeHalf{
|
EdgeHalfList: []*ast.StmtEdgeHalf{
|
||||||
$1.edgeHalf,
|
$1.edgeHalf,
|
||||||
@@ -1207,6 +1207,7 @@ edge:
|
|||||||
},
|
},
|
||||||
//Notify: false, // unused here, it is implied (i think)
|
//Notify: false, // unused here, it is implied (i think)
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.stmt)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
edge_half_list:
|
edge_half_list:
|
||||||
@@ -1225,24 +1226,24 @@ edge_half:
|
|||||||
// eg: Test["t1"]
|
// eg: Test["t1"]
|
||||||
capitalized_res_identifier OPEN_BRACK expr CLOSE_BRACK
|
capitalized_res_identifier OPEN_BRACK expr CLOSE_BRACK
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.edgeHalf = &ast.StmtEdgeHalf{
|
$$.edgeHalf = &ast.StmtEdgeHalf{
|
||||||
Kind: $1.str,
|
Kind: $1.str,
|
||||||
Name: $3.expr,
|
Name: $3.expr,
|
||||||
//SendRecv: "", // unused
|
//SendRecv: "", // unused
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.edgeHalf)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
edge_half_sendrecv:
|
edge_half_sendrecv:
|
||||||
// eg: Test["t1"].foo_send
|
// eg: Test["t1"].foo_send
|
||||||
capitalized_res_identifier OPEN_BRACK expr CLOSE_BRACK DOT IDENTIFIER
|
capitalized_res_identifier OPEN_BRACK expr CLOSE_BRACK DOT IDENTIFIER
|
||||||
{
|
{
|
||||||
posLast(yylex, yyDollar) // our pos
|
|
||||||
$$.edgeHalf = &ast.StmtEdgeHalf{
|
$$.edgeHalf = &ast.StmtEdgeHalf{
|
||||||
Kind: $1.str,
|
Kind: $1.str,
|
||||||
Name: $3.expr,
|
Name: $3.expr,
|
||||||
SendRecv: $6.str,
|
SendRecv: $6.str,
|
||||||
}
|
}
|
||||||
|
locate(yylex, $1, yyDollar[len(yyDollar)-1], $$.edgeHalf)
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
type:
|
type:
|
||||||
@@ -1496,7 +1497,21 @@ func cast(y yyLexer) *lexParseAST {
|
|||||||
return x.(*lexParseAST)
|
return x.(*lexParseAST)
|
||||||
}
|
}
|
||||||
|
|
||||||
// posLast pulls out the "last token" and does a pos with that. This is a hack!
|
// locate should be called after creating AST nodes from lexer tokens to store
|
||||||
|
// the positions of the involved tokens in the AST node.
|
||||||
|
func locate(y yyLexer, first yySymType, last yySymType, node interface{}) {
|
||||||
|
pos(y, last)
|
||||||
|
// Only run Locate on nodes that look like they have not received
|
||||||
|
// locations yet otherwise the parser will come back and overwrite them
|
||||||
|
// with invalid ending positions.
|
||||||
|
if pn, ok := node.(interfaces.PositionableNode); !ok {
|
||||||
|
return
|
||||||
|
} else if !pn.IsSet() {
|
||||||
|
pn.Locate(first.row, first.col, last.row, last.col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// posLast runs pos on the last token of the current stmt/expr.
|
||||||
func posLast(y yyLexer, dollars []yySymType) {
|
func posLast(y yyLexer, dollars []yySymType) {
|
||||||
// pick the last token in the set matched by the parser
|
// pick the last token in the set matched by the parser
|
||||||
pos(y, dollars[len(dollars)-1]) // our pos
|
pos(y, dollars[len(dollars)-1]) // our pos
|
||||||
|
|||||||
@@ -134,9 +134,16 @@ func (obj *FastInvariantSolver) Solve(ctx context.Context, data *unification.Dat
|
|||||||
if err := unificationUtil.Unify(x.Expect, x.Actual); err != nil {
|
if err := unificationUtil.Unify(x.Expect, x.Actual); err != nil {
|
||||||
// Storing the Expr with this invariant is so that we
|
// Storing the Expr with this invariant is so that we
|
||||||
// can generate this more helpful error message here.
|
// can generate this more helpful error message here.
|
||||||
// TODO: Improve this error message!
|
displayer, ok := x.Node.(interfaces.TextDisplayer)
|
||||||
|
if !ok {
|
||||||
|
obj.Logf("not displayable: %v\n", x.Node)
|
||||||
return nil, errwrap.Wrapf(err, "unify error with: %s", x.Expr)
|
return nil, errwrap.Wrapf(err, "unify error with: %s", x.Expr)
|
||||||
}
|
}
|
||||||
|
if highlight := displayer.HighlightText(); highlight != "" {
|
||||||
|
obj.Logf("%s: %s", err.Error(), highlight)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%s: %s", err.Error(), displayer.Byline())
|
||||||
|
}
|
||||||
if obj.Debug {
|
if obj.Debug {
|
||||||
e1, e2 := unificationUtil.Extract(x.Expect), unificationUtil.Extract(x.Actual)
|
e1, e2 := unificationUtil.Extract(x.Expect), unificationUtil.Extract(x.Actual)
|
||||||
obj.Logf("#%"+pad+"d extract(%s): %s -- %s", i, x.Expr, u(e1), u(e2))
|
obj.Logf("#%"+pad+"d extract(%s): %s -- %s", i, x.Expr, u(e1), u(e2))
|
||||||
|
|||||||
@@ -859,6 +859,11 @@ func TestUnification1(t *testing.T) {
|
|||||||
|
|
||||||
data := &interfaces.Data{
|
data := &interfaces.Data{
|
||||||
// TODO: add missing fields here if/when needed
|
// TODO: add missing fields here if/when needed
|
||||||
|
Metadata: &interfaces.Metadata{},
|
||||||
|
SourceFinder: func(string) ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("not implemented")
|
||||||
|
},
|
||||||
|
|
||||||
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
Debug: testing.Verbose(), // set via the -test.v flag to `go test`
|
||||||
Logf: func(format string, v ...interface{}) {
|
Logf: func(format string, v ...interface{}) {
|
||||||
t.Logf(fmt.Sprintf("test #%d", index)+": ast: "+format, v...)
|
t.Logf(fmt.Sprintf("test #%d", index)+": ast: "+format, v...)
|
||||||
|
|||||||
Reference in New Issue
Block a user