mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
test function bodies in parser
A naive test of a function with a body failed because we were not actually looking for or accepting semicolons, but were generating them on printing a thing back out. Changed to require semicolons between statements. This logic may be wrong; for instance, if you have a trailing semicolon on a body, the String() method won't yield the original text exactly.
This commit is contained in:
parent
6383a96ac5
commit
6787a8ec58
3 changed files with 63 additions and 3 deletions
|
|
@ -198,6 +198,8 @@ func CloneStatement(stmt Statement) Statement {
|
|||
return stmt.Clone()
|
||||
case *ReleaseStatement:
|
||||
return stmt.Clone()
|
||||
case *ReturnStatement:
|
||||
return stmt.Clone()
|
||||
case *RollbackStatement:
|
||||
return stmt.Clone()
|
||||
case *SavepointStatement:
|
||||
|
|
@ -3133,7 +3135,10 @@ func (s *CreateFunctionStatement) String() string {
|
|||
|
||||
buf.WriteString(" AS BEGIN")
|
||||
for i := range s.Body {
|
||||
fmt.Fprintf(&buf, " %s;", s.Body[i].String())
|
||||
if i > 0 {
|
||||
buf.WriteString(";")
|
||||
}
|
||||
fmt.Fprintf(&buf, " %s", s.Body[i].String())
|
||||
}
|
||||
buf.WriteString(" END")
|
||||
|
||||
|
|
|
|||
|
|
@ -1610,6 +1610,19 @@ func (p *Parser) parseCreateFunctionStatement(createPos Pos) (_ *CreateFunctionS
|
|||
if p.peek() == END {
|
||||
break
|
||||
}
|
||||
if p.peek() != SEMI {
|
||||
return &stmt, p.errorExpected(p.pos, p.peek(), "semicolon or END")
|
||||
}
|
||||
// we don't have a good place to stash the semicolon's position,
|
||||
// so just consume it.
|
||||
_, _, _ = p.scan()
|
||||
// Allow a trailing semicolon. Note that the trailing semicolon won't
|
||||
// be reproduced by .String(); to fix this, we either have to modify
|
||||
// every statement to track its own semicolon, or the body to track
|
||||
// the positions of semicolons. Either of those might be reasonable.
|
||||
if p.peek() == END {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if p.peek() != END {
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ func TestParser_ParseAlterStatement(t *testing.T) {
|
|||
|
||||
func TestParser_ParseFunctionStatement(t *testing.T) {
|
||||
t.Run("CreateFunction", func(t *testing.T) {
|
||||
AssertParseStatement(t, `CREATE FUNCTION IF NOT EXISTS func (@param1 int, @param2 string) returns int as begin end`, &parser.CreateFunctionStatement{
|
||||
AssertParseStatement(t, `CREATE FUNCTION IF NOT EXISTS func (@param1 int, @param2 string) returns int as begin return 3 end`, &parser.CreateFunctionStatement{
|
||||
Create: pos(0),
|
||||
Function: pos(7),
|
||||
If: pos(16),
|
||||
|
|
@ -495,8 +495,50 @@ func TestParser_ParseFunctionStatement(t *testing.T) {
|
|||
ReturnType: &parser.Type{Name: &parser.Ident{NamePos: pos(73), Name: "int"}},
|
||||
As: pos(77),
|
||||
Begin: pos(80),
|
||||
End: pos(86),
|
||||
Body: []parser.Statement{&parser.ReturnStatement{
|
||||
Return: pos(86),
|
||||
ReturnExpr: &parser.IntegerLit{ValuePos: pos(93), Value: "3"},
|
||||
}},
|
||||
End: pos(95),
|
||||
})
|
||||
// This example is probably invalid, but lets us verify that the semicolons between
|
||||
// statements are working
|
||||
AssertParseStatement(t, `CREATE FUNCTION IF NOT EXISTS func (@param1 int, @param2 string) returns int as begin return 3; return 4 end`, &parser.CreateFunctionStatement{
|
||||
Create: pos(0),
|
||||
Function: pos(7),
|
||||
If: pos(16),
|
||||
IfNot: pos(19),
|
||||
IfNotExists: pos(23),
|
||||
Name: &parser.Ident{NamePos: pos(30), Name: "func"},
|
||||
Lparen: pos(35),
|
||||
Parameters: []*parser.ParameterDefinition{
|
||||
{
|
||||
Name: &parser.Variable{Name: "@param1", NamePos: pos(36)},
|
||||
Type: &parser.Type{Name: &parser.Ident{NamePos: pos(44), Name: "int"}},
|
||||
},
|
||||
{
|
||||
Name: &parser.Variable{Name: "@param2", NamePos: pos(49)},
|
||||
Type: &parser.Type{Name: &parser.Ident{NamePos: pos(57), Name: "string"}},
|
||||
},
|
||||
},
|
||||
Rparen: pos(63),
|
||||
Returns: pos(65),
|
||||
ReturnType: &parser.Type{Name: &parser.Ident{NamePos: pos(73), Name: "int"}},
|
||||
As: pos(77),
|
||||
Begin: pos(80),
|
||||
Body: []parser.Statement{
|
||||
&parser.ReturnStatement{
|
||||
Return: pos(86),
|
||||
ReturnExpr: &parser.IntegerLit{ValuePos: pos(93), Value: "3"},
|
||||
},
|
||||
&parser.ReturnStatement{
|
||||
Return: pos(96),
|
||||
ReturnExpr: &parser.IntegerLit{ValuePos: pos(103), Value: "4"},
|
||||
},
|
||||
},
|
||||
End: pos(105),
|
||||
})
|
||||
AssertParseStatementError(t, `CREATE FUNCTION IF NOT EXISTS func (@param1 int, @param2 string) returns int as begin return 3 return 4 end`, `1:96: expected semicolon or END, found 'RETURN'`)
|
||||
// AssertParseStatement(t, `CREATE TRIGGER IF NOT EXISTS trig BEFORE INSERT ON tbl BEGIN DELETE FROM new; END`, &parser.CreateFunctionStatement{
|
||||
// Create: pos(0),
|
||||
// Function: pos(7),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue